From 99bf5448bd02f9b97f55025725e7d2d4ba9aced8 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 5 Nov 2017 11:37:05 +0200 Subject: axtls: Update, exposes AES functions to implement ECB chiper mode. --- lib/axtls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/axtls b/lib/axtls index dac9176ca..43a6e6bd3 160000 --- a/lib/axtls +++ b/lib/axtls @@ -1 +1 @@ -Subproject commit dac9176cac58cc5e49669a9a4d404a6f6dd7cc10 +Subproject commit 43a6e6bd3bbc03dc501e16b89fba0ef042ed3ea0 -- cgit v1.2.3 From 4601759bf59e16b860a3f082e9aa4ea78356bf92 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 16 Nov 2017 13:17:51 +1100 Subject: py/objstr: Remove "make_qstr_if_not_already" arg from mp_obj_new_str. This patch simplifies the str creation API to favour the common case of creating a str object that is not forced to be interned. To force interning of a new str the new mp_obj_new_str_via_qstr function is added, and should only be used if warranted. Apart from simplifying the mp_obj_new_str function (and making it have the same signature as mp_obj_new_bytes), this patch also reduces code size by a bit (-16 bytes for bare-arm and roughly -40 bytes on the bare-metal archs). --- extmod/modujson.c | 2 +- extmod/modwebrepl.c | 2 +- extmod/vfs_fat.c | 2 +- extmod/vfs_fat_misc.c | 2 +- extmod/vfs_reader.c | 2 +- lib/netutils/netutils.c | 2 +- ports/cc3200/mods/modwlan.c | 10 +++++----- ports/esp8266/modnetwork.c | 4 ++-- ports/esp8266/moduos.c | 2 +- ports/stm32/modnwcc3k.c | 4 ++-- ports/unix/coverage.c | 6 +++--- ports/unix/main.c | 6 +++--- ports/unix/modffi.c | 2 +- ports/unix/modjni.c | 2 +- ports/unix/modos.c | 4 ++-- ports/zephyr/modusocket.c | 2 +- py/binary.c | 2 +- py/builtinhelp.c | 2 +- py/builtinimport.c | 2 +- py/modbuiltins.c | 4 ++-- py/modio.c | 2 +- py/obj.h | 3 ++- py/objstr.c | 36 ++++++++++++++++++------------------ py/objstrunicode.c | 4 ++-- 24 files changed, 55 insertions(+), 54 deletions(-) (limited to 'lib') diff --git a/extmod/modujson.c b/extmod/modujson.c index f14682d26..6eeba4ed6 100644 --- a/extmod/modujson.c +++ b/extmod/modujson.c @@ -166,7 +166,7 @@ STATIC mp_obj_t mod_ujson_load(mp_obj_t stream_obj) { goto fail; } S_NEXT(s); - next = mp_obj_new_str(vstr.buf, vstr.len, false); + next = mp_obj_new_str(vstr.buf, vstr.len); break; case '-': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { diff --git a/extmod/modwebrepl.c b/extmod/modwebrepl.c index 3aba5c0f1..42b30f5ea 100644 --- a/extmod/modwebrepl.c +++ b/extmod/modwebrepl.c @@ -141,7 +141,7 @@ STATIC void handle_op(mp_obj_webrepl_t *self) { // Handle operations requiring opened file mp_obj_t open_args[2] = { - mp_obj_new_str(self->hdr.fname, strlen(self->hdr.fname), false), + mp_obj_new_str(self->hdr.fname, strlen(self->hdr.fname)), MP_OBJ_NEW_QSTR(MP_QSTR_rb) }; diff --git a/extmod/vfs_fat.c b/extmod/vfs_fat.c index 22346bdf1..9942ddeb5 100644 --- a/extmod/vfs_fat.c +++ b/extmod/vfs_fat.c @@ -197,7 +197,7 @@ STATIC mp_obj_t fat_vfs_getcwd(mp_obj_t vfs_in) { if (res != FR_OK) { mp_raise_OSError(fresult_to_errno_table[res]); } - return mp_obj_new_str(buf, strlen(buf), false); + return mp_obj_new_str(buf, strlen(buf)); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_getcwd_obj, fat_vfs_getcwd); diff --git a/extmod/vfs_fat_misc.c b/extmod/vfs_fat_misc.c index 9a26b4a2f..1f90ac14c 100644 --- a/extmod/vfs_fat_misc.c +++ b/extmod/vfs_fat_misc.c @@ -57,7 +57,7 @@ STATIC mp_obj_t mp_vfs_fat_ilistdir_it_iternext(mp_obj_t self_in) { // make 3-tuple with info about this entry mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL)); if (self->is_str) { - t->items[0] = mp_obj_new_str(fn, strlen(fn), false); + t->items[0] = mp_obj_new_str(fn, strlen(fn)); } else { t->items[0] = mp_obj_new_bytes((const byte*)fn, strlen(fn)); } diff --git a/extmod/vfs_reader.c b/extmod/vfs_reader.c index 891098aa1..e1ee45a3c 100644 --- a/extmod/vfs_reader.c +++ b/extmod/vfs_reader.c @@ -71,7 +71,7 @@ STATIC void mp_reader_vfs_close(void *data) { void mp_reader_new_file(mp_reader_t *reader, const char *filename) { mp_reader_vfs_t *rf = m_new_obj(mp_reader_vfs_t); - mp_obj_t arg = mp_obj_new_str(filename, strlen(filename), false); + mp_obj_t arg = mp_obj_new_str(filename, strlen(filename)); rf->file = mp_vfs_open(1, &arg, (mp_map_t*)&mp_const_empty_map); int errcode; rf->len = mp_stream_rw(rf->file, rf->buf, sizeof(rf->buf), &errcode, MP_STREAM_RW_READ | MP_STREAM_RW_ONCE); diff --git a/lib/netutils/netutils.c b/lib/netutils/netutils.c index 06c3ff9b0..073f46b19 100644 --- a/lib/netutils/netutils.c +++ b/lib/netutils/netutils.c @@ -41,7 +41,7 @@ mp_obj_t netutils_format_ipv4_addr(uint8_t *ip, netutils_endian_t endian) { } else { ip_len = snprintf(ip_str, 16, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]); } - return mp_obj_new_str(ip_str, ip_len, false); + return mp_obj_new_str(ip_str, ip_len); } // Takes an array with a raw IP address, and a port, and returns a net-address diff --git a/ports/cc3200/mods/modwlan.c b/ports/cc3200/mods/modwlan.c index f9c7111b3..8acc89da3 100644 --- a/ports/cc3200/mods/modwlan.c +++ b/ports/cc3200/mods/modwlan.c @@ -885,7 +885,7 @@ STATIC mp_obj_t wlan_scan(mp_obj_t self_in) { } mp_obj_t tuple[5]; - tuple[0] = mp_obj_new_str((const char *)wlanEntry.ssid, wlanEntry.ssid_len, false); + tuple[0] = mp_obj_new_str((const char *)wlanEntry.ssid, wlanEntry.ssid_len); tuple[1] = mp_obj_new_bytes((const byte *)wlanEntry.bssid, SL_BSSID_LENGTH); // 'normalize' the security type if (wlanEntry.sec_type > 2) { @@ -1075,7 +1075,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(wlan_mode_obj, 1, 2, wlan_mode); STATIC mp_obj_t wlan_ssid(size_t n_args, const mp_obj_t *args) { wlan_obj_t *self = args[0]; if (n_args == 1) { - return mp_obj_new_str((const char *)self->ssid, strlen((const char *)self->ssid), false); + return mp_obj_new_str((const char *)self->ssid, strlen((const char *)self->ssid)); } else { size_t len; const char *ssid = mp_obj_str_get_data(args[1], &len); @@ -1095,7 +1095,7 @@ STATIC mp_obj_t wlan_auth(size_t n_args, const mp_obj_t *args) { } else { mp_obj_t security[2]; security[0] = mp_obj_new_int(self->auth); - security[1] = mp_obj_new_str((const char *)self->key, strlen((const char *)self->key), false); + security[1] = mp_obj_new_str((const char *)self->key, strlen((const char *)self->key)); return mp_obj_new_tuple(2, security); } } else { @@ -1199,7 +1199,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(wlan_irq_obj, 1, wlan_irq); // mp_obj_t connections = mp_obj_new_list(0, NULL); // // if (wlan_is_connected()) { -// device[0] = mp_obj_new_str((const char *)wlan_obj.ssid_o, strlen((const char *)wlan_obj.ssid_o), false); +// device[0] = mp_obj_new_str((const char *)wlan_obj.ssid_o, strlen((const char *)wlan_obj.ssid_o)); // device[1] = mp_obj_new_bytes((const byte *)wlan_obj.bssid, SL_BSSID_LENGTH); // // add the device to the list // mp_obj_list_append(connections, mp_obj_new_tuple(MP_ARRAY_SIZE(device), device)); @@ -1232,7 +1232,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(wlan_irq_obj, 1, wlan_irq); // if (sl_NetAppGet(SL_NET_APP_DEVICE_CONFIG_ID, NETAPP_SET_GET_DEV_CONF_OPT_DEVICE_URN, &len, (uint8_t *)urn) < 0) { // mp_raise_OSError(MP_EIO); // } -// return mp_obj_new_str(urn, (len - 1), false); +// return mp_obj_new_str(urn, (len - 1)); // } // // return mp_const_none; diff --git a/ports/esp8266/modnetwork.c b/ports/esp8266/modnetwork.c index b41a11f59..4066c969c 100644 --- a/ports/esp8266/modnetwork.c +++ b/ports/esp8266/modnetwork.c @@ -411,7 +411,7 @@ STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs } case QS(MP_QSTR_essid): req_if = SOFTAP_IF; - val = mp_obj_new_str((char*)cfg.ap.ssid, cfg.ap.ssid_len, false); + val = mp_obj_new_str((char*)cfg.ap.ssid, cfg.ap.ssid_len); break; case QS(MP_QSTR_hidden): req_if = SOFTAP_IF; @@ -428,7 +428,7 @@ STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs 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); + val = mp_obj_new_str(s, strlen(s)); break; } default: diff --git a/ports/esp8266/moduos.c b/ports/esp8266/moduos.c index d0554096e..93f7aa712 100644 --- a/ports/esp8266/moduos.c +++ b/ports/esp8266/moduos.c @@ -60,7 +60,7 @@ STATIC mp_obj_tuple_t os_uname_info_obj = { STATIC mp_obj_t os_uname(void) { // We must populate the "release" field each time in case it was GC'd since the last call. const char *ver = system_get_sdk_version(); - os_uname_info_obj.items[2] = mp_obj_new_str(ver, strlen(ver), false); + os_uname_info_obj.items[2] = mp_obj_new_str(ver, strlen(ver)); return (mp_obj_t)&os_uname_info_obj; } STATIC MP_DEFINE_CONST_FUN_OBJ_0(os_uname_obj, os_uname); diff --git a/ports/stm32/modnwcc3k.c b/ports/stm32/modnwcc3k.c index 8cc0a613d..4f1af7354 100644 --- a/ports/stm32/modnwcc3k.c +++ b/ports/stm32/modnwcc3k.c @@ -531,8 +531,8 @@ STATIC mp_obj_t cc3k_ifconfig(mp_obj_t self_in) { netutils_format_ipv4_addr(ipconfig.aucDefaultGateway, NETUTILS_LITTLE), netutils_format_ipv4_addr(ipconfig.aucDNSServer, NETUTILS_LITTLE), netutils_format_ipv4_addr(ipconfig.aucDHCPServer, NETUTILS_LITTLE), - mp_obj_new_str(mac_vstr.buf, mac_vstr.len, false), - mp_obj_new_str((const char*)ipconfig.uaSSID, strlen((const char*)ipconfig.uaSSID), false), + mp_obj_new_str(mac_vstr.buf, mac_vstr.len), + mp_obj_new_str((const char*)ipconfig.uaSSID, strlen((const char*)ipconfig.uaSSID)), }; return mp_obj_new_tuple(MP_ARRAY_SIZE(tuple), tuple); } diff --git a/ports/unix/coverage.c b/ports/unix/coverage.c index 651db0a94..e2896c2dd 100644 --- a/ports/unix/coverage.c +++ b/ports/unix/coverage.c @@ -227,7 +227,7 @@ STATIC mp_obj_t extra_coverage(void) { mp_printf(&mp_plat_print, "# str\n"); // intern string - mp_printf(&mp_plat_print, "%d\n", MP_OBJ_IS_QSTR(mp_obj_str_intern(mp_obj_new_str("intern me", 9, false)))); + mp_printf(&mp_plat_print, "%d\n", MP_OBJ_IS_QSTR(mp_obj_str_intern(mp_obj_new_str("intern me", 9)))); } // mpz @@ -260,12 +260,12 @@ STATIC mp_obj_t extra_coverage(void) { // call mp_call_function_1_protected mp_call_function_1_protected(MP_OBJ_FROM_PTR(&mp_builtin_abs_obj), MP_OBJ_NEW_SMALL_INT(1)); // call mp_call_function_1_protected with invalid args - mp_call_function_1_protected(MP_OBJ_FROM_PTR(&mp_builtin_abs_obj), mp_obj_new_str("abc", 3, false)); + mp_call_function_1_protected(MP_OBJ_FROM_PTR(&mp_builtin_abs_obj), mp_obj_new_str("abc", 3)); // call mp_call_function_2_protected mp_call_function_2_protected(MP_OBJ_FROM_PTR(&mp_builtin_divmod_obj), MP_OBJ_NEW_SMALL_INT(1), MP_OBJ_NEW_SMALL_INT(1)); // call mp_call_function_2_protected with invalid args - mp_call_function_2_protected(MP_OBJ_FROM_PTR(&mp_builtin_divmod_obj), mp_obj_new_str("abc", 3, false), mp_obj_new_str("abc", 3, false)); + mp_call_function_2_protected(MP_OBJ_FROM_PTR(&mp_builtin_divmod_obj), mp_obj_new_str("abc", 3), mp_obj_new_str("abc", 3)); } // warning diff --git a/ports/unix/main.c b/ports/unix/main.c index e1cd33fc1..25f3e04fb 100644 --- a/ports/unix/main.c +++ b/ports/unix/main.c @@ -481,7 +481,7 @@ MP_NOINLINE int main_(int argc, char **argv) { vstr_add_strn(&vstr, p + 1, p1 - p - 1); path_items[i] = mp_obj_new_str_from_vstr(&mp_type_str, &vstr); } else { - path_items[i] = MP_OBJ_NEW_QSTR(qstr_from_strn(p, p1 - p)); + path_items[i] = mp_obj_new_str_via_qstr(p, p1 - p); } p = p1 + 1; } @@ -537,7 +537,7 @@ MP_NOINLINE int main_(int argc, char **argv) { return usage(argv); } mp_obj_t import_args[4]; - import_args[0] = mp_obj_new_str(argv[a + 1], strlen(argv[a + 1]), false); + import_args[0] = mp_obj_new_str(argv[a + 1], strlen(argv[a + 1])); import_args[1] = import_args[2] = mp_const_none; // Ask __import__ to handle imported module specially - set its __name__ // to __main__, and also return this leaf module, not top-level package @@ -603,7 +603,7 @@ MP_NOINLINE int main_(int argc, char **argv) { // Set base dir of the script as first entry in sys.path char *p = strrchr(basedir, '/'); - path_items[0] = MP_OBJ_NEW_QSTR(qstr_from_strn(basedir, p - basedir)); + path_items[0] = mp_obj_new_str_via_qstr(basedir, p - basedir); free(pathbuf); set_sys_argv(argv, argc, a); diff --git a/ports/unix/modffi.c b/ports/unix/modffi.c index 78adccac1..024f83c14 100644 --- a/ports/unix/modffi.c +++ b/ports/unix/modffi.c @@ -144,7 +144,7 @@ STATIC mp_obj_t return_ffi_value(ffi_arg val, char type) if (!s) { return mp_const_none; } - return mp_obj_new_str(s, strlen(s), false); + return mp_obj_new_str(s, strlen(s)); } case 'v': return mp_const_none; diff --git a/ports/unix/modjni.c b/ports/unix/modjni.c index f29c095cf..8ec5ae54d 100644 --- a/ports/unix/modjni.c +++ b/ports/unix/modjni.c @@ -337,7 +337,7 @@ STATIC mp_obj_t new_jobject(jobject jo) { return mp_const_none; } else if (JJ(IsInstanceOf, jo, String_class)) { const char *s = JJ(GetStringUTFChars, jo, NULL); - mp_obj_t ret = mp_obj_new_str(s, strlen(s), false); + mp_obj_t ret = mp_obj_new_str(s, strlen(s)); JJ(ReleaseStringUTFChars, jo, s); return ret; } else if (JJ(IsInstanceOf, jo, Class_class)) { diff --git a/ports/unix/modos.c b/ports/unix/modos.c index 327116a0a..808d12adb 100644 --- a/ports/unix/modos.c +++ b/ports/unix/modos.c @@ -133,7 +133,7 @@ STATIC mp_obj_t mod_os_getenv(mp_obj_t var_in) { if (s == NULL) { return mp_const_none; } - return mp_obj_new_str(s, strlen(s), false); + return mp_obj_new_str(s, strlen(s)); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_os_getenv_obj, mod_os_getenv); @@ -171,7 +171,7 @@ STATIC mp_obj_t listdir_next(mp_obj_t self_in) { } mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL)); - t->items[0] = mp_obj_new_str(dirent->d_name, strlen(dirent->d_name), false); + t->items[0] = mp_obj_new_str(dirent->d_name, strlen(dirent->d_name)); #ifdef _DIRENT_HAVE_D_TYPE t->items[1] = MP_OBJ_NEW_SMALL_INT(dirent->d_type); #else diff --git a/ports/zephyr/modusocket.c b/ports/zephyr/modusocket.c index e021c3a44..95414a49b 100644 --- a/ports/zephyr/modusocket.c +++ b/ports/zephyr/modusocket.c @@ -91,7 +91,7 @@ STATIC mp_obj_t format_inet_addr(struct sockaddr *addr, mp_obj_t port) { net_addr_ntop(addr->sa_family, &sockaddr_in6->sin6_addr, buf, sizeof(buf)); mp_obj_tuple_t *tuple = mp_obj_new_tuple(addr->sa_family == AF_INET ? 2 : 4, NULL); - tuple->items[0] = mp_obj_new_str(buf, strlen(buf), false); + tuple->items[0] = mp_obj_new_str(buf, strlen(buf)); // We employ the fact that port offset is the same for IPv4 & IPv6 // not filled in //tuple->items[1] = mp_obj_new_int(ntohs(((struct sockaddr_in*)addr)->sin_port)); diff --git a/py/binary.c b/py/binary.c index 870a0942b..f509ff010 100644 --- a/py/binary.c +++ b/py/binary.c @@ -206,7 +206,7 @@ mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr) { return (mp_obj_t)(mp_uint_t)val; } else if (val_type == 'S') { const char *s_val = (const char*)(uintptr_t)(mp_uint_t)val; - return mp_obj_new_str(s_val, strlen(s_val), false); + return mp_obj_new_str(s_val, strlen(s_val)); #if MICROPY_PY_BUILTINS_FLOAT } else if (val_type == 'f') { union { uint32_t i; float f; } fpu = {val}; diff --git a/py/builtinhelp.c b/py/builtinhelp.c index c9992906d..7106f3ced 100644 --- a/py/builtinhelp.c +++ b/py/builtinhelp.c @@ -69,7 +69,7 @@ STATIC void mp_help_add_from_names(mp_obj_t list, const char *name) { while (*name) { size_t l = strlen(name); // name should end in '.py' and we strip it off - mp_obj_list_append(list, mp_obj_new_str(name, l - 3, false)); + mp_obj_list_append(list, mp_obj_new_str(name, l - 3)); name += l + 1; } } diff --git a/py/builtinimport.c b/py/builtinimport.c index 04ce66723..9235e946c 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -434,7 +434,7 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { DEBUG_printf("%.*s is dir\n", vstr_len(&path), vstr_str(&path)); // https://docs.python.org/3/reference/import.html // "Specifically, any module that contains a __path__ attribute is considered a package." - mp_store_attr(module_obj, MP_QSTR___path__, mp_obj_new_str(vstr_str(&path), vstr_len(&path), false)); + mp_store_attr(module_obj, MP_QSTR___path__, mp_obj_new_str(vstr_str(&path), vstr_len(&path))); size_t orig_path_len = path.len; vstr_add_char(&path, PATH_SEP_CHAR); vstr_add_str(&path, "__init__.py"); diff --git a/py/modbuiltins.c b/py/modbuiltins.c index 65c03d523..ebff5f5c0 100644 --- a/py/modbuiltins.c +++ b/py/modbuiltins.c @@ -159,12 +159,12 @@ STATIC mp_obj_t mp_builtin_chr(mp_obj_t o_in) { } else { mp_raise_ValueError("chr() arg not in range(0x110000)"); } - return mp_obj_new_str(str, len, true); + return mp_obj_new_str_via_qstr(str, len); #else mp_int_t ord = mp_obj_get_int(o_in); if (0 <= ord && ord <= 0xff) { char str[1] = {ord}; - return mp_obj_new_str(str, 1, true); + return mp_obj_new_str_via_qstr(str, 1); } else { mp_raise_ValueError("chr() arg not in range(256)"); } diff --git a/py/modio.c b/py/modio.c index 353a00286..828bcec46 100644 --- a/py/modio.c +++ b/py/modio.c @@ -176,7 +176,7 @@ STATIC mp_obj_t resource_stream(mp_obj_t package_in, mp_obj_t path_in) { return MP_OBJ_FROM_PTR(o); } - mp_obj_t path_out = mp_obj_new_str(path_buf.buf, path_buf.len, false); + mp_obj_t path_out = mp_obj_new_str(path_buf.buf, path_buf.len); return mp_builtin_open(1, &path_out, (mp_map_t*)&mp_const_empty_map); } MP_DEFINE_CONST_FUN_OBJ_2(resource_stream_obj, resource_stream); diff --git a/py/obj.h b/py/obj.h index 77f0f2298..31c3ce95c 100644 --- a/py/obj.h +++ b/py/obj.h @@ -637,7 +637,8 @@ mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value); mp_obj_t mp_obj_new_int_from_str_len(const char **str, size_t len, bool neg, unsigned int base); mp_obj_t mp_obj_new_int_from_ll(long long val); // this must return a multi-precision integer object (or raise an overflow exception) mp_obj_t mp_obj_new_int_from_ull(unsigned long long val); // this must return a multi-precision integer object (or raise an overflow exception) -mp_obj_t mp_obj_new_str(const char* data, size_t len, bool make_qstr_if_not_already); +mp_obj_t mp_obj_new_str(const char* data, size_t len); +mp_obj_t mp_obj_new_str_via_qstr(const char* data, size_t len); mp_obj_t mp_obj_new_str_from_vstr(const mp_obj_type_t *type, vstr_t *vstr); mp_obj_t mp_obj_new_bytes(const byte* data, size_t len); mp_obj_t mp_obj_new_bytearray(size_t n, void *items); diff --git a/py/objstr.c b/py/objstr.c index 51da7a418..5c464ba7d 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -176,7 +176,7 @@ mp_obj_t mp_obj_str_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_ mp_raise_msg(&mp_type_UnicodeError, NULL); } #endif - return mp_obj_new_str(bufinfo.buf, bufinfo.len, false); + return mp_obj_new_str(bufinfo.buf, bufinfo.len); } } } @@ -423,7 +423,7 @@ STATIC mp_obj_t bytes_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { if (MICROPY_PY_BUILTINS_STR_UNICODE || type == &mp_type_bytes) { return MP_OBJ_NEW_SMALL_INT(self_data[index_val]); } else { - return mp_obj_new_str((char*)&self_data[index_val], 1, true); + return mp_obj_new_str_via_qstr((char*)&self_data[index_val], 1); } } else { return MP_OBJ_NULL; // op not supported @@ -1046,7 +1046,7 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar } else { const char *lookup; for (lookup = field_name; lookup < field_name_top && *lookup != '.' && *lookup != '['; lookup++); - mp_obj_t field_q = mp_obj_new_str(field_name, lookup - field_name, true/*?*/); + mp_obj_t field_q = mp_obj_new_str_via_qstr(field_name, lookup - field_name); // should it be via qstr? field_name = lookup; mp_map_elem_t *key_elem = mp_map_lookup(kwargs, field_q, MP_MAP_LOOKUP); if (key_elem == NULL) { @@ -1413,7 +1413,7 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_ } ++str; } - mp_obj_t k_obj = mp_obj_new_str((const char*)key, str - key, true); + mp_obj_t k_obj = mp_obj_new_str_via_qstr((const char*)key, str - key); arg = mp_obj_dict_get(dict, k_obj); str++; } @@ -1992,6 +1992,11 @@ mp_obj_t mp_obj_new_str_of_type(const mp_obj_type_t *type, const byte* data, siz return MP_OBJ_FROM_PTR(o); } +// Create a str using a qstr to store the data; may use existing or new qstr. +mp_obj_t mp_obj_new_str_via_qstr(const char* data, size_t len) { + return MP_OBJ_NEW_QSTR(qstr_from_strn(data, len)); +} + // Create a str/bytes object from the given vstr. The vstr buffer is resized to // the exact length required and then reused for the str/bytes object. The vstr // is cleared and can safely be passed to vstr_free if it was heap allocated. @@ -2022,25 +2027,20 @@ mp_obj_t mp_obj_new_str_from_vstr(const mp_obj_type_t *type, vstr_t *vstr) { return MP_OBJ_FROM_PTR(o); } -mp_obj_t mp_obj_new_str(const char* data, size_t len, bool make_qstr_if_not_already) { - if (make_qstr_if_not_already) { - // use existing, or make a new qstr - return MP_OBJ_NEW_QSTR(qstr_from_strn(data, len)); +mp_obj_t mp_obj_new_str(const char* data, size_t len) { + qstr q = qstr_find_strn(data, len); + if (q != MP_QSTR_NULL) { + // qstr with this data already exists + return MP_OBJ_NEW_QSTR(q); } else { - qstr q = qstr_find_strn(data, len); - if (q != MP_QSTR_NULL) { - // qstr with this data already exists - return MP_OBJ_NEW_QSTR(q); - } else { - // no existing qstr, don't make one - return mp_obj_new_str_of_type(&mp_type_str, (const byte*)data, len); - } + // no existing qstr, don't make one + return mp_obj_new_str_of_type(&mp_type_str, (const byte*)data, len); } } mp_obj_t mp_obj_str_intern(mp_obj_t str) { GET_STR_DATA_LEN(str, data, len); - return MP_OBJ_NEW_QSTR(qstr_from_strn((const char*)data, len)); + return mp_obj_new_str_via_qstr((const char*)data, len); } mp_obj_t mp_obj_new_bytes(const byte* data, size_t len) { @@ -2138,7 +2138,7 @@ STATIC mp_obj_t str_it_iternext(mp_obj_t self_in) { mp_obj_str8_it_t *self = MP_OBJ_TO_PTR(self_in); GET_STR_DATA_LEN(self->str, str, len); if (self->cur < len) { - mp_obj_t o_out = mp_obj_new_str((const char*)str + self->cur, 1, true); + mp_obj_t o_out = mp_obj_new_str_via_qstr((const char*)str + self->cur, 1); self->cur += 1; return o_out; } else { diff --git a/py/objstrunicode.c b/py/objstrunicode.c index 29f7695b7..a1f54b8a2 100644 --- a/py/objstrunicode.c +++ b/py/objstrunicode.c @@ -216,7 +216,7 @@ STATIC mp_obj_t str_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { ++len; } } - return mp_obj_new_str((const char*)s, len, true); // This will create a one-character string + return mp_obj_new_str_via_qstr((const char*)s, len); // This will create a one-character string } else { return MP_OBJ_NULL; // op not supported } @@ -291,7 +291,7 @@ STATIC mp_obj_t str_it_iternext(mp_obj_t self_in) { if (self->cur < len) { const byte *cur = str + self->cur; const byte *end = utf8_next_char(str + self->cur); - mp_obj_t o_out = mp_obj_new_str((const char*)cur, end - cur, true); + mp_obj_t o_out = mp_obj_new_str_via_qstr((const char*)cur, end - cur); self->cur += end - cur; return o_out; } else { -- cgit v1.2.3 From e9d29c9ba997ae0f00f16f3a21dffce7c763a3d4 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Fri, 8 Dec 2017 19:26:15 +0200 Subject: lib/tinytest: Move from tools/tinytest. Tinytest library was misplaced under tools/. By convention, any target libraries belong to lib/, while tools/ contains host-side tools. --- lib/tinytest/README | 18 ++ lib/tinytest/tinytest.c | 474 +++++++++++++++++++++++++++++++++++++++ lib/tinytest/tinytest.h | 98 ++++++++ lib/tinytest/tinytest_macros.h | 184 +++++++++++++++ ports/qemu-arm/Makefile | 6 +- tools/tinytest/README | 18 -- tools/tinytest/tinytest.c | 474 --------------------------------------- tools/tinytest/tinytest.h | 98 -------- tools/tinytest/tinytest_macros.h | 184 --------------- 9 files changed, 778 insertions(+), 776 deletions(-) create mode 100644 lib/tinytest/README create mode 100644 lib/tinytest/tinytest.c create mode 100644 lib/tinytest/tinytest.h create mode 100644 lib/tinytest/tinytest_macros.h delete mode 100644 tools/tinytest/README delete mode 100644 tools/tinytest/tinytest.c delete mode 100644 tools/tinytest/tinytest.h delete mode 100644 tools/tinytest/tinytest_macros.h (limited to 'lib') diff --git a/lib/tinytest/README b/lib/tinytest/README new file mode 100644 index 000000000..902c4a2e0 --- /dev/null +++ b/lib/tinytest/README @@ -0,0 +1,18 @@ +Tinytest is a tiny little test framework written in C by Nick Mathewson. + +It is distributed under the 3-clause BSD license. You can use it in +your own programs so long as you follow the license's conditions. + +It's been tested on Windows, Mac, and many of the free Unixes. + +It knows how to fork before running certain tests, and it makes +text-mode output in a format I like. + +For info on how to use it, check out tinytest_demo.c. + +You can get the latest version using Git, by pulling from + git://github.com/nmathewson/tinytest.git + +Patches are welcome. Patches that turn this from tinytest to hugetest +will not be applied. If you want a huge test framework, use CUnit. + diff --git a/lib/tinytest/tinytest.c b/lib/tinytest/tinytest.c new file mode 100644 index 000000000..1ef957d31 --- /dev/null +++ b/lib/tinytest/tinytest.c @@ -0,0 +1,474 @@ +/* tinytest.c -- Copyright 2009-2012 Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifdef TINYTEST_LOCAL +#include "tinytest_local.h" +#endif + +#include +#include +#include +#include + +#ifndef NO_FORKING + +#ifdef _WIN32 +#include +#else +#include +#include +#include +#endif + +#if defined(__APPLE__) && defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) +#if (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1060 && \ + __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070) +/* Workaround for a stupid bug in OSX 10.6 */ +#define FORK_BREAKS_GCOV +#include +#endif +#endif + +#endif /* !NO_FORKING */ + +#ifndef __GNUC__ +#define __attribute__(x) +#endif + +#include "tinytest.h" +#include "tinytest_macros.h" + +#define LONGEST_TEST_NAME 16384 + +static int in_tinytest_main = 0; /**< true if we're in tinytest_main().*/ +static int n_ok = 0; /**< Number of tests that have passed */ +static int n_bad = 0; /**< Number of tests that have failed. */ +static int n_skipped = 0; /**< Number of tests that have been skipped. */ + +static int opt_forked = 0; /**< True iff we're called from inside a win32 fork*/ +static int opt_nofork = 0; /**< Suppress calls to fork() for debugging. */ +static int opt_verbosity = 1; /**< -==quiet,0==terse,1==normal,2==verbose */ +const char *verbosity_flag = ""; + +const struct testlist_alias_t *cfg_aliases=NULL; + +enum outcome { SKIP=2, OK=1, FAIL=0 }; +static enum outcome cur_test_outcome = 0; +const char *cur_test_prefix = NULL; /**< prefix of the current test group */ +/** Name of the current test, if we haven't logged is yet. Used for --quiet */ +const char *cur_test_name = NULL; + +#ifdef _WIN32 +/* Copy of argv[0] for win32. */ +static char commandname[MAX_PATH+1]; +#endif + +static void usage(struct testgroup_t *groups, int list_groups) + __attribute__((noreturn)); +static int process_test_option(struct testgroup_t *groups, const char *test); + +static enum outcome +testcase_run_bare_(const struct testcase_t *testcase) +{ + void *env = NULL; + int outcome; + if (testcase->setup) { + env = testcase->setup->setup_fn(testcase); + if (!env) + return FAIL; + else if (env == (void*)TT_SKIP) + return SKIP; + } + + cur_test_outcome = OK; + testcase->fn(env); + outcome = cur_test_outcome; + + if (testcase->setup) { + if (testcase->setup->cleanup_fn(testcase, env) == 0) + outcome = FAIL; + } + + return outcome; +} + +#define MAGIC_EXITCODE 42 + +#ifndef NO_FORKING + +static enum outcome +testcase_run_forked_(const struct testgroup_t *group, + const struct testcase_t *testcase) +{ +#ifdef _WIN32 + /* Fork? On Win32? How primitive! We'll do what the smart kids do: + we'll invoke our own exe (whose name we recall from the command + line) with a command line that tells it to run just the test we + want, and this time without forking. + + (No, threads aren't an option. The whole point of forking is to + share no state between tests.) + */ + int ok; + char buffer[LONGEST_TEST_NAME+256]; + STARTUPINFOA si; + PROCESS_INFORMATION info; + DWORD exitcode; + + if (!in_tinytest_main) { + printf("\nERROR. On Windows, testcase_run_forked_ must be" + " called from within tinytest_main.\n"); + abort(); + } + if (opt_verbosity>0) + printf("[forking] "); + + snprintf(buffer, sizeof(buffer), "%s --RUNNING-FORKED %s %s%s", + commandname, verbosity_flag, group->prefix, testcase->name); + + memset(&si, 0, sizeof(si)); + memset(&info, 0, sizeof(info)); + si.cb = sizeof(si); + + ok = CreateProcessA(commandname, buffer, NULL, NULL, 0, + 0, NULL, NULL, &si, &info); + if (!ok) { + printf("CreateProcess failed!\n"); + return 0; + } + WaitForSingleObject(info.hProcess, INFINITE); + GetExitCodeProcess(info.hProcess, &exitcode); + CloseHandle(info.hProcess); + CloseHandle(info.hThread); + if (exitcode == 0) + return OK; + else if (exitcode == MAGIC_EXITCODE) + return SKIP; + else + return FAIL; +#else + int outcome_pipe[2]; + pid_t pid; + (void)group; + + if (pipe(outcome_pipe)) + perror("opening pipe"); + + if (opt_verbosity>0) + printf("[forking] "); + pid = fork(); +#ifdef FORK_BREAKS_GCOV + vproc_transaction_begin(0); +#endif + if (!pid) { + /* child. */ + int test_r, write_r; + char b[1]; + close(outcome_pipe[0]); + test_r = testcase_run_bare_(testcase); + assert(0<=(int)test_r && (int)test_r<=2); + b[0] = "NYS"[test_r]; + write_r = (int)write(outcome_pipe[1], b, 1); + if (write_r != 1) { + perror("write outcome to pipe"); + exit(1); + } + exit(0); + return FAIL; /* unreachable */ + } else { + /* parent */ + int status, r; + char b[1]; + /* Close this now, so that if the other side closes it, + * our read fails. */ + close(outcome_pipe[1]); + r = (int)read(outcome_pipe[0], b, 1); + if (r == 0) { + printf("[Lost connection!] "); + return 0; + } else if (r != 1) { + perror("read outcome from pipe"); + } + waitpid(pid, &status, 0); + close(outcome_pipe[0]); + return b[0]=='Y' ? OK : (b[0]=='S' ? SKIP : FAIL); + } +#endif +} + +#endif /* !NO_FORKING */ + +int +testcase_run_one(const struct testgroup_t *group, + const struct testcase_t *testcase) +{ + enum outcome outcome; + + if (testcase->flags & (TT_SKIP|TT_OFF_BY_DEFAULT)) { + if (opt_verbosity>0) + printf("%s%s: %s\n", + group->prefix, testcase->name, + (testcase->flags & TT_SKIP) ? "SKIPPED" : "DISABLED"); + ++n_skipped; + return SKIP; + } + + if (opt_verbosity>0 && !opt_forked) { + printf("%s%s: ", group->prefix, testcase->name); + } else { + if (opt_verbosity==0) printf("."); + cur_test_prefix = group->prefix; + cur_test_name = testcase->name; + } + +#ifndef NO_FORKING + if ((testcase->flags & TT_FORK) && !(opt_forked||opt_nofork)) { + outcome = testcase_run_forked_(group, testcase); + } else { +#else + { +#endif + outcome = testcase_run_bare_(testcase); + } + + if (outcome == OK) { + ++n_ok; + if (opt_verbosity>0 && !opt_forked) + puts(opt_verbosity==1?"OK":""); + } else if (outcome == SKIP) { + ++n_skipped; + if (opt_verbosity>0 && !opt_forked) + puts("SKIPPED"); + } else { + ++n_bad; + if (!opt_forked) + printf("\n [%s FAILED]\n", testcase->name); + } + + if (opt_forked) { + exit(outcome==OK ? 0 : (outcome==SKIP?MAGIC_EXITCODE : 1)); + return 1; /* unreachable */ + } else { + return (int)outcome; + } +} + +int +tinytest_set_flag_(struct testgroup_t *groups, const char *arg, int set, unsigned long flag) +{ + int i, j; + size_t length = LONGEST_TEST_NAME; + char fullname[LONGEST_TEST_NAME]; + int found=0; + if (strstr(arg, "..")) + length = strstr(arg,"..")-arg; + for (i=0; groups[i].prefix; ++i) { + for (j=0; groups[i].cases[j].name; ++j) { + struct testcase_t *testcase = &groups[i].cases[j]; + snprintf(fullname, sizeof(fullname), "%s%s", + groups[i].prefix, testcase->name); + if (!flag) { /* Hack! */ + printf(" %s", fullname); + if (testcase->flags & TT_OFF_BY_DEFAULT) + puts(" (Off by default)"); + else if (testcase->flags & TT_SKIP) + puts(" (DISABLED)"); + else + puts(""); + } + if (!strncmp(fullname, arg, length)) { + if (set) + testcase->flags |= flag; + else + testcase->flags &= ~flag; + ++found; + } + } + } + return found; +} + +static void +usage(struct testgroup_t *groups, int list_groups) +{ + puts("Options are: [--verbose|--quiet|--terse] [--no-fork]"); + puts(" Specify tests by name, or using a prefix ending with '..'"); + puts(" To skip a test, prefix its name with a colon."); + puts(" To enable a disabled test, prefix its name with a plus."); + puts(" Use --list-tests for a list of tests."); + if (list_groups) { + puts("Known tests are:"); + tinytest_set_flag_(groups, "..", 1, 0); + } + exit(0); +} + +static int +process_test_alias(struct testgroup_t *groups, const char *test) +{ + int i, j, n, r; + for (i=0; cfg_aliases && cfg_aliases[i].name; ++i) { + if (!strcmp(cfg_aliases[i].name, test)) { + n = 0; + for (j = 0; cfg_aliases[i].tests[j]; ++j) { + r = process_test_option(groups, cfg_aliases[i].tests[j]); + if (r<0) + return -1; + n += r; + } + return n; + } + } + printf("No such test alias as @%s!",test); + return -1; +} + +static int +process_test_option(struct testgroup_t *groups, const char *test) +{ + int flag = TT_ENABLED_; + int n = 0; + if (test[0] == '@') { + return process_test_alias(groups, test + 1); + } else if (test[0] == ':') { + ++test; + flag = TT_SKIP; + } else if (test[0] == '+') { + ++test; + ++n; + if (!tinytest_set_flag_(groups, test, 0, TT_OFF_BY_DEFAULT)) { + printf("No such test as %s!\n", test); + return -1; + } + } else { + ++n; + } + if (!tinytest_set_flag_(groups, test, 1, flag)) { + printf("No such test as %s!\n", test); + return -1; + } + return n; +} + +void +tinytest_set_aliases(const struct testlist_alias_t *aliases) +{ + cfg_aliases = aliases; +} + +int +tinytest_main(int c, const char **v, struct testgroup_t *groups) +{ + int i, j, n=0; + +#ifdef _WIN32 + const char *sp = strrchr(v[0], '.'); + const char *extension = ""; + if (!sp || stricmp(sp, ".exe")) + extension = ".exe"; /* Add an exe so CreateProcess will work */ + snprintf(commandname, sizeof(commandname), "%s%s", v[0], extension); + commandname[MAX_PATH]='\0'; +#endif + for (i=1; i= 1) + printf("%d tests ok. (%d skipped)\n", n_ok, n_skipped); + + return (n_bad == 0) ? 0 : 1; +} + +int +tinytest_get_verbosity_(void) +{ + return opt_verbosity; +} + +void +tinytest_set_test_failed_(void) +{ + if (opt_verbosity <= 0 && cur_test_name) { + if (opt_verbosity==0) puts(""); + printf("%s%s: ", cur_test_prefix, cur_test_name); + cur_test_name = NULL; + } + cur_test_outcome = 0; +} + +void +tinytest_set_test_skipped_(void) +{ + if (cur_test_outcome==OK) + cur_test_outcome = SKIP; +} + diff --git a/lib/tinytest/tinytest.h b/lib/tinytest/tinytest.h new file mode 100644 index 000000000..dff440e31 --- /dev/null +++ b/lib/tinytest/tinytest.h @@ -0,0 +1,98 @@ +/* tinytest.h -- Copyright 2009-2012 Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TINYTEST_H_INCLUDED_ +#define TINYTEST_H_INCLUDED_ + +/** Flag for a test that needs to run in a subprocess. */ +#define TT_FORK (1<<0) +/** Runtime flag for a test we've decided to skip. */ +#define TT_SKIP (1<<1) +/** Internal runtime flag for a test we've decided to run. */ +#define TT_ENABLED_ (1<<2) +/** Flag for a test that's off by default. */ +#define TT_OFF_BY_DEFAULT (1<<3) +/** If you add your own flags, make them start at this point. */ +#define TT_FIRST_USER_FLAG (1<<4) + +typedef void (*testcase_fn)(void *); + +struct testcase_t; + +/** Functions to initialize/teardown a structure for a testcase. */ +struct testcase_setup_t { + /** Return a new structure for use by a given testcase. */ + void *(*setup_fn)(const struct testcase_t *); + /** Clean/free a structure from setup_fn. Return 1 if ok, 0 on err. */ + int (*cleanup_fn)(const struct testcase_t *, void *); +}; + +/** A single test-case that you can run. */ +struct testcase_t { + const char *name; /**< An identifier for this case. */ + testcase_fn fn; /**< The function to run to implement this case. */ + unsigned long flags; /**< Bitfield of TT_* flags. */ + const struct testcase_setup_t *setup; /**< Optional setup/cleanup fns*/ + void *setup_data; /**< Extra data usable by setup function */ +}; +#define END_OF_TESTCASES { NULL, NULL, 0, NULL, NULL } + +/** A group of tests that are selectable together. */ +struct testgroup_t { + const char *prefix; /**< Prefix to prepend to testnames. */ + struct testcase_t *cases; /** Array, ending with END_OF_TESTCASES */ +}; +#define END_OF_GROUPS { NULL, NULL} + +struct testlist_alias_t { + const char *name; + const char **tests; +}; +#define END_OF_ALIASES { NULL, NULL } + +/** Implementation: called from a test to indicate failure, before logging. */ +void tinytest_set_test_failed_(void); +/** Implementation: called from a test to indicate that we're skipping. */ +void tinytest_set_test_skipped_(void); +/** Implementation: return 0 for quiet, 1 for normal, 2 for loud. */ +int tinytest_get_verbosity_(void); +/** Implementation: Set a flag on tests matching a name; returns number + * of tests that matched. */ +int tinytest_set_flag_(struct testgroup_t *, const char *, int set, unsigned long); + +/** Set all tests in 'groups' matching the name 'named' to be skipped. */ +#define tinytest_skip(groups, named) \ + tinytest_set_flag_(groups, named, 1, TT_SKIP) + +/** Run a single testcase in a single group. */ +int testcase_run_one(const struct testgroup_t *,const struct testcase_t *); + +void tinytest_set_aliases(const struct testlist_alias_t *aliases); + +/** Run a set of testcases from an END_OF_GROUPS-terminated array of groups, + as selected from the command line. */ +int tinytest_main(int argc, const char **argv, struct testgroup_t *groups); + +#endif diff --git a/lib/tinytest/tinytest_macros.h b/lib/tinytest/tinytest_macros.h new file mode 100644 index 000000000..9ff69b1d5 --- /dev/null +++ b/lib/tinytest/tinytest_macros.h @@ -0,0 +1,184 @@ +/* tinytest_macros.h -- Copyright 2009-2012 Nick Mathewson + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TINYTEST_MACROS_H_INCLUDED_ +#define TINYTEST_MACROS_H_INCLUDED_ + +/* Helpers for defining statement-like macros */ +#define TT_STMT_BEGIN do { +#define TT_STMT_END } while (0) + +/* Redefine this if your test functions want to abort with something besides + * "goto end;" */ +#ifndef TT_EXIT_TEST_FUNCTION +#define TT_EXIT_TEST_FUNCTION TT_STMT_BEGIN goto end; TT_STMT_END +#endif + +/* Redefine this if you want to note success/failure in some different way. */ +#ifndef TT_DECLARE +#define TT_DECLARE(prefix, args) \ + TT_STMT_BEGIN \ + printf("\n %s %s:%d: ",prefix,__FILE__,__LINE__); \ + printf args ; \ + TT_STMT_END +#endif + +/* Announce a failure. Args are parenthesized printf args. */ +#define TT_GRIPE(args) TT_DECLARE("FAIL", args) + +/* Announce a non-failure if we're verbose. */ +#define TT_BLATHER(args) \ + TT_STMT_BEGIN \ + if (tinytest_get_verbosity_()>1) TT_DECLARE(" OK", args); \ + TT_STMT_END + +#define TT_DIE(args) \ + TT_STMT_BEGIN \ + tinytest_set_test_failed_(); \ + TT_GRIPE(args); \ + TT_EXIT_TEST_FUNCTION; \ + TT_STMT_END + +#define TT_FAIL(args) \ + TT_STMT_BEGIN \ + tinytest_set_test_failed_(); \ + TT_GRIPE(args); \ + TT_STMT_END + +/* Fail and abort the current test for the reason in msg */ +#define tt_abort_printf(msg) TT_DIE(msg) +#define tt_abort_perror(op) TT_DIE(("%s: %s [%d]",(op),strerror(errno), errno)) +#define tt_abort_msg(msg) TT_DIE(("%s", msg)) +#define tt_abort() TT_DIE(("%s", "(Failed.)")) + +/* Fail but do not abort the current test for the reason in msg. */ +#define tt_failprint_f(msg) TT_FAIL(msg) +#define tt_fail_perror(op) TT_FAIL(("%s: %s [%d]",(op),strerror(errno), errno)) +#define tt_fail_msg(msg) TT_FAIL(("%s", msg)) +#define tt_fail() TT_FAIL(("%s", "(Failed.)")) + +/* End the current test, and indicate we are skipping it. */ +#define tt_skip() \ + TT_STMT_BEGIN \ + tinytest_set_test_skipped_(); \ + TT_EXIT_TEST_FUNCTION; \ + TT_STMT_END + +#define tt_want_(b, msg, fail) \ + TT_STMT_BEGIN \ + if (!(b)) { \ + tinytest_set_test_failed_(); \ + TT_GRIPE(("%s",msg)); \ + fail; \ + } else { \ + TT_BLATHER(("%s",msg)); \ + } \ + TT_STMT_END + +/* Assert b, but do not stop the test if b fails. Log msg on failure. */ +#define tt_want_msg(b, msg) \ + tt_want_(b, msg, ); + +/* Assert b and stop the test if b fails. Log msg on failure. */ +#define tt_assert_msg(b, msg) \ + tt_want_(b, msg, TT_EXIT_TEST_FUNCTION); + +/* Assert b, but do not stop the test if b fails. */ +#define tt_want(b) tt_want_msg( (b), "want("#b")") +/* Assert b, and stop the test if b fails. */ +#define tt_assert(b) tt_assert_msg((b), "assert("#b")") + +#define tt_assert_test_fmt_type(a,b,str_test,type,test,printf_type,printf_fmt, \ + setup_block,cleanup_block,die_on_fail) \ + TT_STMT_BEGIN \ + type val1_ = (type)(a); \ + type val2_ = (type)(b); \ + int tt_status_ = (test); \ + if (!tt_status_ || tinytest_get_verbosity_()>1) { \ + printf_type print_; \ + printf_type print1_; \ + printf_type print2_; \ + type value_ = val1_; \ + setup_block; \ + print1_ = print_; \ + value_ = val2_; \ + setup_block; \ + print2_ = print_; \ + TT_DECLARE(tt_status_?" OK":"FAIL", \ + ("assert(%s): "printf_fmt" vs "printf_fmt, \ + str_test, print1_, print2_)); \ + print_ = print1_; \ + cleanup_block; \ + print_ = print2_; \ + cleanup_block; \ + if (!tt_status_) { \ + tinytest_set_test_failed_(); \ + die_on_fail ; \ + } \ + } \ + TT_STMT_END + +#define tt_assert_test_type(a,b,str_test,type,test,fmt,die_on_fail) \ + tt_assert_test_fmt_type(a,b,str_test,type,test,type,fmt, \ + {print_=value_;},{},die_on_fail) + +/* Helper: assert that a op b, when cast to type. Format the values with + * printf format fmt on failure. */ +#define tt_assert_op_type(a,op,b,type,fmt) \ + tt_assert_test_type(a,b,#a" "#op" "#b,type,(val1_ op val2_),fmt, \ + TT_EXIT_TEST_FUNCTION) + +#define tt_int_op(a,op,b) \ + tt_assert_test_type(a,b,#a" "#op" "#b,long,(val1_ op val2_), \ + "%ld",TT_EXIT_TEST_FUNCTION) + +#define tt_uint_op(a,op,b) \ + tt_assert_test_type(a,b,#a" "#op" "#b,unsigned long, \ + (val1_ op val2_),"%lu",TT_EXIT_TEST_FUNCTION) + +#define tt_ptr_op(a,op,b) \ + tt_assert_test_type(a,b,#a" "#op" "#b,void*, \ + (val1_ op val2_),"%p",TT_EXIT_TEST_FUNCTION) + +#define tt_str_op(a,op,b) \ + tt_assert_test_type(a,b,#a" "#op" "#b,const char *, \ + (strcmp(val1_,val2_) op 0),"<%s>",TT_EXIT_TEST_FUNCTION) + +#define tt_want_int_op(a,op,b) \ + tt_assert_test_type(a,b,#a" "#op" "#b,long,(val1_ op val2_),"%ld",(void)0) + +#define tt_want_uint_op(a,op,b) \ + tt_assert_test_type(a,b,#a" "#op" "#b,unsigned long, \ + (val1_ op val2_),"%lu",(void)0) + +#define tt_want_ptr_op(a,op,b) \ + tt_assert_test_type(a,b,#a" "#op" "#b,void*, \ + (val1_ op val2_),"%p",(void)0) + +#define tt_want_str_op(a,op,b) \ + tt_assert_test_type(a,b,#a" "#op" "#b,const char *, \ + (strcmp(val1_,val2_) op 0),"<%s>",(void)0) + +#endif diff --git a/ports/qemu-arm/Makefile b/ports/qemu-arm/Makefile index 39e13853f..c0d257a3e 100644 --- a/ports/qemu-arm/Makefile +++ b/ports/qemu-arm/Makefile @@ -9,10 +9,12 @@ include $(TOP)/py/py.mk CROSS_COMPILE = arm-none-eabi- +TINYTEST = $(TOP)/lib/tinytest + INC += -I. INC += -I$(TOP) INC += -I$(BUILD) -INC += -I$(TOP)/tools/tinytest/ +INC += -I$(TINYTEST) CFLAGS_CORTEX_M3 = -mthumb -mcpu=cortex-m3 -mfloat-abi=soft CFLAGS = $(INC) -Wall -Wpointer-arith -Werror -std=gnu99 $(CFLAGS_CORTEX_M3) $(COPT) \ @@ -101,7 +103,7 @@ $(BUILD)/genhdr/tests.h: $(Q)echo "Generating $@";(cd $(TOP)/tests; ../tools/tinytest-codegen.py) > $@ $(BUILD)/tinytest.o: - $(Q)$(CC) $(CFLAGS) -DNO_FORKING -o $@ -c $(TOP)/tools/tinytest/tinytest.c + $(Q)$(CC) $(CFLAGS) -DNO_FORKING -o $@ -c $(TINYTEST)/tinytest.c ## `$(LD)` doesn't seem to like `--specs` for some reason, but we can just use `$(CC)` here. $(BUILD)/firmware.elf: $(OBJ_COMMON) $(OBJ_RUN) diff --git a/tools/tinytest/README b/tools/tinytest/README deleted file mode 100644 index 902c4a2e0..000000000 --- a/tools/tinytest/README +++ /dev/null @@ -1,18 +0,0 @@ -Tinytest is a tiny little test framework written in C by Nick Mathewson. - -It is distributed under the 3-clause BSD license. You can use it in -your own programs so long as you follow the license's conditions. - -It's been tested on Windows, Mac, and many of the free Unixes. - -It knows how to fork before running certain tests, and it makes -text-mode output in a format I like. - -For info on how to use it, check out tinytest_demo.c. - -You can get the latest version using Git, by pulling from - git://github.com/nmathewson/tinytest.git - -Patches are welcome. Patches that turn this from tinytest to hugetest -will not be applied. If you want a huge test framework, use CUnit. - diff --git a/tools/tinytest/tinytest.c b/tools/tinytest/tinytest.c deleted file mode 100644 index 1ef957d31..000000000 --- a/tools/tinytest/tinytest.c +++ /dev/null @@ -1,474 +0,0 @@ -/* tinytest.c -- Copyright 2009-2012 Nick Mathewson - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#ifdef TINYTEST_LOCAL -#include "tinytest_local.h" -#endif - -#include -#include -#include -#include - -#ifndef NO_FORKING - -#ifdef _WIN32 -#include -#else -#include -#include -#include -#endif - -#if defined(__APPLE__) && defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) -#if (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1060 && \ - __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070) -/* Workaround for a stupid bug in OSX 10.6 */ -#define FORK_BREAKS_GCOV -#include -#endif -#endif - -#endif /* !NO_FORKING */ - -#ifndef __GNUC__ -#define __attribute__(x) -#endif - -#include "tinytest.h" -#include "tinytest_macros.h" - -#define LONGEST_TEST_NAME 16384 - -static int in_tinytest_main = 0; /**< true if we're in tinytest_main().*/ -static int n_ok = 0; /**< Number of tests that have passed */ -static int n_bad = 0; /**< Number of tests that have failed. */ -static int n_skipped = 0; /**< Number of tests that have been skipped. */ - -static int opt_forked = 0; /**< True iff we're called from inside a win32 fork*/ -static int opt_nofork = 0; /**< Suppress calls to fork() for debugging. */ -static int opt_verbosity = 1; /**< -==quiet,0==terse,1==normal,2==verbose */ -const char *verbosity_flag = ""; - -const struct testlist_alias_t *cfg_aliases=NULL; - -enum outcome { SKIP=2, OK=1, FAIL=0 }; -static enum outcome cur_test_outcome = 0; -const char *cur_test_prefix = NULL; /**< prefix of the current test group */ -/** Name of the current test, if we haven't logged is yet. Used for --quiet */ -const char *cur_test_name = NULL; - -#ifdef _WIN32 -/* Copy of argv[0] for win32. */ -static char commandname[MAX_PATH+1]; -#endif - -static void usage(struct testgroup_t *groups, int list_groups) - __attribute__((noreturn)); -static int process_test_option(struct testgroup_t *groups, const char *test); - -static enum outcome -testcase_run_bare_(const struct testcase_t *testcase) -{ - void *env = NULL; - int outcome; - if (testcase->setup) { - env = testcase->setup->setup_fn(testcase); - if (!env) - return FAIL; - else if (env == (void*)TT_SKIP) - return SKIP; - } - - cur_test_outcome = OK; - testcase->fn(env); - outcome = cur_test_outcome; - - if (testcase->setup) { - if (testcase->setup->cleanup_fn(testcase, env) == 0) - outcome = FAIL; - } - - return outcome; -} - -#define MAGIC_EXITCODE 42 - -#ifndef NO_FORKING - -static enum outcome -testcase_run_forked_(const struct testgroup_t *group, - const struct testcase_t *testcase) -{ -#ifdef _WIN32 - /* Fork? On Win32? How primitive! We'll do what the smart kids do: - we'll invoke our own exe (whose name we recall from the command - line) with a command line that tells it to run just the test we - want, and this time without forking. - - (No, threads aren't an option. The whole point of forking is to - share no state between tests.) - */ - int ok; - char buffer[LONGEST_TEST_NAME+256]; - STARTUPINFOA si; - PROCESS_INFORMATION info; - DWORD exitcode; - - if (!in_tinytest_main) { - printf("\nERROR. On Windows, testcase_run_forked_ must be" - " called from within tinytest_main.\n"); - abort(); - } - if (opt_verbosity>0) - printf("[forking] "); - - snprintf(buffer, sizeof(buffer), "%s --RUNNING-FORKED %s %s%s", - commandname, verbosity_flag, group->prefix, testcase->name); - - memset(&si, 0, sizeof(si)); - memset(&info, 0, sizeof(info)); - si.cb = sizeof(si); - - ok = CreateProcessA(commandname, buffer, NULL, NULL, 0, - 0, NULL, NULL, &si, &info); - if (!ok) { - printf("CreateProcess failed!\n"); - return 0; - } - WaitForSingleObject(info.hProcess, INFINITE); - GetExitCodeProcess(info.hProcess, &exitcode); - CloseHandle(info.hProcess); - CloseHandle(info.hThread); - if (exitcode == 0) - return OK; - else if (exitcode == MAGIC_EXITCODE) - return SKIP; - else - return FAIL; -#else - int outcome_pipe[2]; - pid_t pid; - (void)group; - - if (pipe(outcome_pipe)) - perror("opening pipe"); - - if (opt_verbosity>0) - printf("[forking] "); - pid = fork(); -#ifdef FORK_BREAKS_GCOV - vproc_transaction_begin(0); -#endif - if (!pid) { - /* child. */ - int test_r, write_r; - char b[1]; - close(outcome_pipe[0]); - test_r = testcase_run_bare_(testcase); - assert(0<=(int)test_r && (int)test_r<=2); - b[0] = "NYS"[test_r]; - write_r = (int)write(outcome_pipe[1], b, 1); - if (write_r != 1) { - perror("write outcome to pipe"); - exit(1); - } - exit(0); - return FAIL; /* unreachable */ - } else { - /* parent */ - int status, r; - char b[1]; - /* Close this now, so that if the other side closes it, - * our read fails. */ - close(outcome_pipe[1]); - r = (int)read(outcome_pipe[0], b, 1); - if (r == 0) { - printf("[Lost connection!] "); - return 0; - } else if (r != 1) { - perror("read outcome from pipe"); - } - waitpid(pid, &status, 0); - close(outcome_pipe[0]); - return b[0]=='Y' ? OK : (b[0]=='S' ? SKIP : FAIL); - } -#endif -} - -#endif /* !NO_FORKING */ - -int -testcase_run_one(const struct testgroup_t *group, - const struct testcase_t *testcase) -{ - enum outcome outcome; - - if (testcase->flags & (TT_SKIP|TT_OFF_BY_DEFAULT)) { - if (opt_verbosity>0) - printf("%s%s: %s\n", - group->prefix, testcase->name, - (testcase->flags & TT_SKIP) ? "SKIPPED" : "DISABLED"); - ++n_skipped; - return SKIP; - } - - if (opt_verbosity>0 && !opt_forked) { - printf("%s%s: ", group->prefix, testcase->name); - } else { - if (opt_verbosity==0) printf("."); - cur_test_prefix = group->prefix; - cur_test_name = testcase->name; - } - -#ifndef NO_FORKING - if ((testcase->flags & TT_FORK) && !(opt_forked||opt_nofork)) { - outcome = testcase_run_forked_(group, testcase); - } else { -#else - { -#endif - outcome = testcase_run_bare_(testcase); - } - - if (outcome == OK) { - ++n_ok; - if (opt_verbosity>0 && !opt_forked) - puts(opt_verbosity==1?"OK":""); - } else if (outcome == SKIP) { - ++n_skipped; - if (opt_verbosity>0 && !opt_forked) - puts("SKIPPED"); - } else { - ++n_bad; - if (!opt_forked) - printf("\n [%s FAILED]\n", testcase->name); - } - - if (opt_forked) { - exit(outcome==OK ? 0 : (outcome==SKIP?MAGIC_EXITCODE : 1)); - return 1; /* unreachable */ - } else { - return (int)outcome; - } -} - -int -tinytest_set_flag_(struct testgroup_t *groups, const char *arg, int set, unsigned long flag) -{ - int i, j; - size_t length = LONGEST_TEST_NAME; - char fullname[LONGEST_TEST_NAME]; - int found=0; - if (strstr(arg, "..")) - length = strstr(arg,"..")-arg; - for (i=0; groups[i].prefix; ++i) { - for (j=0; groups[i].cases[j].name; ++j) { - struct testcase_t *testcase = &groups[i].cases[j]; - snprintf(fullname, sizeof(fullname), "%s%s", - groups[i].prefix, testcase->name); - if (!flag) { /* Hack! */ - printf(" %s", fullname); - if (testcase->flags & TT_OFF_BY_DEFAULT) - puts(" (Off by default)"); - else if (testcase->flags & TT_SKIP) - puts(" (DISABLED)"); - else - puts(""); - } - if (!strncmp(fullname, arg, length)) { - if (set) - testcase->flags |= flag; - else - testcase->flags &= ~flag; - ++found; - } - } - } - return found; -} - -static void -usage(struct testgroup_t *groups, int list_groups) -{ - puts("Options are: [--verbose|--quiet|--terse] [--no-fork]"); - puts(" Specify tests by name, or using a prefix ending with '..'"); - puts(" To skip a test, prefix its name with a colon."); - puts(" To enable a disabled test, prefix its name with a plus."); - puts(" Use --list-tests for a list of tests."); - if (list_groups) { - puts("Known tests are:"); - tinytest_set_flag_(groups, "..", 1, 0); - } - exit(0); -} - -static int -process_test_alias(struct testgroup_t *groups, const char *test) -{ - int i, j, n, r; - for (i=0; cfg_aliases && cfg_aliases[i].name; ++i) { - if (!strcmp(cfg_aliases[i].name, test)) { - n = 0; - for (j = 0; cfg_aliases[i].tests[j]; ++j) { - r = process_test_option(groups, cfg_aliases[i].tests[j]); - if (r<0) - return -1; - n += r; - } - return n; - } - } - printf("No such test alias as @%s!",test); - return -1; -} - -static int -process_test_option(struct testgroup_t *groups, const char *test) -{ - int flag = TT_ENABLED_; - int n = 0; - if (test[0] == '@') { - return process_test_alias(groups, test + 1); - } else if (test[0] == ':') { - ++test; - flag = TT_SKIP; - } else if (test[0] == '+') { - ++test; - ++n; - if (!tinytest_set_flag_(groups, test, 0, TT_OFF_BY_DEFAULT)) { - printf("No such test as %s!\n", test); - return -1; - } - } else { - ++n; - } - if (!tinytest_set_flag_(groups, test, 1, flag)) { - printf("No such test as %s!\n", test); - return -1; - } - return n; -} - -void -tinytest_set_aliases(const struct testlist_alias_t *aliases) -{ - cfg_aliases = aliases; -} - -int -tinytest_main(int c, const char **v, struct testgroup_t *groups) -{ - int i, j, n=0; - -#ifdef _WIN32 - const char *sp = strrchr(v[0], '.'); - const char *extension = ""; - if (!sp || stricmp(sp, ".exe")) - extension = ".exe"; /* Add an exe so CreateProcess will work */ - snprintf(commandname, sizeof(commandname), "%s%s", v[0], extension); - commandname[MAX_PATH]='\0'; -#endif - for (i=1; i= 1) - printf("%d tests ok. (%d skipped)\n", n_ok, n_skipped); - - return (n_bad == 0) ? 0 : 1; -} - -int -tinytest_get_verbosity_(void) -{ - return opt_verbosity; -} - -void -tinytest_set_test_failed_(void) -{ - if (opt_verbosity <= 0 && cur_test_name) { - if (opt_verbosity==0) puts(""); - printf("%s%s: ", cur_test_prefix, cur_test_name); - cur_test_name = NULL; - } - cur_test_outcome = 0; -} - -void -tinytest_set_test_skipped_(void) -{ - if (cur_test_outcome==OK) - cur_test_outcome = SKIP; -} - diff --git a/tools/tinytest/tinytest.h b/tools/tinytest/tinytest.h deleted file mode 100644 index dff440e31..000000000 --- a/tools/tinytest/tinytest.h +++ /dev/null @@ -1,98 +0,0 @@ -/* tinytest.h -- Copyright 2009-2012 Nick Mathewson - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TINYTEST_H_INCLUDED_ -#define TINYTEST_H_INCLUDED_ - -/** Flag for a test that needs to run in a subprocess. */ -#define TT_FORK (1<<0) -/** Runtime flag for a test we've decided to skip. */ -#define TT_SKIP (1<<1) -/** Internal runtime flag for a test we've decided to run. */ -#define TT_ENABLED_ (1<<2) -/** Flag for a test that's off by default. */ -#define TT_OFF_BY_DEFAULT (1<<3) -/** If you add your own flags, make them start at this point. */ -#define TT_FIRST_USER_FLAG (1<<4) - -typedef void (*testcase_fn)(void *); - -struct testcase_t; - -/** Functions to initialize/teardown a structure for a testcase. */ -struct testcase_setup_t { - /** Return a new structure for use by a given testcase. */ - void *(*setup_fn)(const struct testcase_t *); - /** Clean/free a structure from setup_fn. Return 1 if ok, 0 on err. */ - int (*cleanup_fn)(const struct testcase_t *, void *); -}; - -/** A single test-case that you can run. */ -struct testcase_t { - const char *name; /**< An identifier for this case. */ - testcase_fn fn; /**< The function to run to implement this case. */ - unsigned long flags; /**< Bitfield of TT_* flags. */ - const struct testcase_setup_t *setup; /**< Optional setup/cleanup fns*/ - void *setup_data; /**< Extra data usable by setup function */ -}; -#define END_OF_TESTCASES { NULL, NULL, 0, NULL, NULL } - -/** A group of tests that are selectable together. */ -struct testgroup_t { - const char *prefix; /**< Prefix to prepend to testnames. */ - struct testcase_t *cases; /** Array, ending with END_OF_TESTCASES */ -}; -#define END_OF_GROUPS { NULL, NULL} - -struct testlist_alias_t { - const char *name; - const char **tests; -}; -#define END_OF_ALIASES { NULL, NULL } - -/** Implementation: called from a test to indicate failure, before logging. */ -void tinytest_set_test_failed_(void); -/** Implementation: called from a test to indicate that we're skipping. */ -void tinytest_set_test_skipped_(void); -/** Implementation: return 0 for quiet, 1 for normal, 2 for loud. */ -int tinytest_get_verbosity_(void); -/** Implementation: Set a flag on tests matching a name; returns number - * of tests that matched. */ -int tinytest_set_flag_(struct testgroup_t *, const char *, int set, unsigned long); - -/** Set all tests in 'groups' matching the name 'named' to be skipped. */ -#define tinytest_skip(groups, named) \ - tinytest_set_flag_(groups, named, 1, TT_SKIP) - -/** Run a single testcase in a single group. */ -int testcase_run_one(const struct testgroup_t *,const struct testcase_t *); - -void tinytest_set_aliases(const struct testlist_alias_t *aliases); - -/** Run a set of testcases from an END_OF_GROUPS-terminated array of groups, - as selected from the command line. */ -int tinytest_main(int argc, const char **argv, struct testgroup_t *groups); - -#endif diff --git a/tools/tinytest/tinytest_macros.h b/tools/tinytest/tinytest_macros.h deleted file mode 100644 index 9ff69b1d5..000000000 --- a/tools/tinytest/tinytest_macros.h +++ /dev/null @@ -1,184 +0,0 @@ -/* tinytest_macros.h -- Copyright 2009-2012 Nick Mathewson - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TINYTEST_MACROS_H_INCLUDED_ -#define TINYTEST_MACROS_H_INCLUDED_ - -/* Helpers for defining statement-like macros */ -#define TT_STMT_BEGIN do { -#define TT_STMT_END } while (0) - -/* Redefine this if your test functions want to abort with something besides - * "goto end;" */ -#ifndef TT_EXIT_TEST_FUNCTION -#define TT_EXIT_TEST_FUNCTION TT_STMT_BEGIN goto end; TT_STMT_END -#endif - -/* Redefine this if you want to note success/failure in some different way. */ -#ifndef TT_DECLARE -#define TT_DECLARE(prefix, args) \ - TT_STMT_BEGIN \ - printf("\n %s %s:%d: ",prefix,__FILE__,__LINE__); \ - printf args ; \ - TT_STMT_END -#endif - -/* Announce a failure. Args are parenthesized printf args. */ -#define TT_GRIPE(args) TT_DECLARE("FAIL", args) - -/* Announce a non-failure if we're verbose. */ -#define TT_BLATHER(args) \ - TT_STMT_BEGIN \ - if (tinytest_get_verbosity_()>1) TT_DECLARE(" OK", args); \ - TT_STMT_END - -#define TT_DIE(args) \ - TT_STMT_BEGIN \ - tinytest_set_test_failed_(); \ - TT_GRIPE(args); \ - TT_EXIT_TEST_FUNCTION; \ - TT_STMT_END - -#define TT_FAIL(args) \ - TT_STMT_BEGIN \ - tinytest_set_test_failed_(); \ - TT_GRIPE(args); \ - TT_STMT_END - -/* Fail and abort the current test for the reason in msg */ -#define tt_abort_printf(msg) TT_DIE(msg) -#define tt_abort_perror(op) TT_DIE(("%s: %s [%d]",(op),strerror(errno), errno)) -#define tt_abort_msg(msg) TT_DIE(("%s", msg)) -#define tt_abort() TT_DIE(("%s", "(Failed.)")) - -/* Fail but do not abort the current test for the reason in msg. */ -#define tt_failprint_f(msg) TT_FAIL(msg) -#define tt_fail_perror(op) TT_FAIL(("%s: %s [%d]",(op),strerror(errno), errno)) -#define tt_fail_msg(msg) TT_FAIL(("%s", msg)) -#define tt_fail() TT_FAIL(("%s", "(Failed.)")) - -/* End the current test, and indicate we are skipping it. */ -#define tt_skip() \ - TT_STMT_BEGIN \ - tinytest_set_test_skipped_(); \ - TT_EXIT_TEST_FUNCTION; \ - TT_STMT_END - -#define tt_want_(b, msg, fail) \ - TT_STMT_BEGIN \ - if (!(b)) { \ - tinytest_set_test_failed_(); \ - TT_GRIPE(("%s",msg)); \ - fail; \ - } else { \ - TT_BLATHER(("%s",msg)); \ - } \ - TT_STMT_END - -/* Assert b, but do not stop the test if b fails. Log msg on failure. */ -#define tt_want_msg(b, msg) \ - tt_want_(b, msg, ); - -/* Assert b and stop the test if b fails. Log msg on failure. */ -#define tt_assert_msg(b, msg) \ - tt_want_(b, msg, TT_EXIT_TEST_FUNCTION); - -/* Assert b, but do not stop the test if b fails. */ -#define tt_want(b) tt_want_msg( (b), "want("#b")") -/* Assert b, and stop the test if b fails. */ -#define tt_assert(b) tt_assert_msg((b), "assert("#b")") - -#define tt_assert_test_fmt_type(a,b,str_test,type,test,printf_type,printf_fmt, \ - setup_block,cleanup_block,die_on_fail) \ - TT_STMT_BEGIN \ - type val1_ = (type)(a); \ - type val2_ = (type)(b); \ - int tt_status_ = (test); \ - if (!tt_status_ || tinytest_get_verbosity_()>1) { \ - printf_type print_; \ - printf_type print1_; \ - printf_type print2_; \ - type value_ = val1_; \ - setup_block; \ - print1_ = print_; \ - value_ = val2_; \ - setup_block; \ - print2_ = print_; \ - TT_DECLARE(tt_status_?" OK":"FAIL", \ - ("assert(%s): "printf_fmt" vs "printf_fmt, \ - str_test, print1_, print2_)); \ - print_ = print1_; \ - cleanup_block; \ - print_ = print2_; \ - cleanup_block; \ - if (!tt_status_) { \ - tinytest_set_test_failed_(); \ - die_on_fail ; \ - } \ - } \ - TT_STMT_END - -#define tt_assert_test_type(a,b,str_test,type,test,fmt,die_on_fail) \ - tt_assert_test_fmt_type(a,b,str_test,type,test,type,fmt, \ - {print_=value_;},{},die_on_fail) - -/* Helper: assert that a op b, when cast to type. Format the values with - * printf format fmt on failure. */ -#define tt_assert_op_type(a,op,b,type,fmt) \ - tt_assert_test_type(a,b,#a" "#op" "#b,type,(val1_ op val2_),fmt, \ - TT_EXIT_TEST_FUNCTION) - -#define tt_int_op(a,op,b) \ - tt_assert_test_type(a,b,#a" "#op" "#b,long,(val1_ op val2_), \ - "%ld",TT_EXIT_TEST_FUNCTION) - -#define tt_uint_op(a,op,b) \ - tt_assert_test_type(a,b,#a" "#op" "#b,unsigned long, \ - (val1_ op val2_),"%lu",TT_EXIT_TEST_FUNCTION) - -#define tt_ptr_op(a,op,b) \ - tt_assert_test_type(a,b,#a" "#op" "#b,void*, \ - (val1_ op val2_),"%p",TT_EXIT_TEST_FUNCTION) - -#define tt_str_op(a,op,b) \ - tt_assert_test_type(a,b,#a" "#op" "#b,const char *, \ - (strcmp(val1_,val2_) op 0),"<%s>",TT_EXIT_TEST_FUNCTION) - -#define tt_want_int_op(a,op,b) \ - tt_assert_test_type(a,b,#a" "#op" "#b,long,(val1_ op val2_),"%ld",(void)0) - -#define tt_want_uint_op(a,op,b) \ - tt_assert_test_type(a,b,#a" "#op" "#b,unsigned long, \ - (val1_ op val2_),"%lu",(void)0) - -#define tt_want_ptr_op(a,op,b) \ - tt_assert_test_type(a,b,#a" "#op" "#b,void*, \ - (val1_ op val2_),"%p",(void)0) - -#define tt_want_str_op(a,op,b) \ - tt_assert_test_type(a,b,#a" "#op" "#b,const char *, \ - (strcmp(val1_,val2_) op 0),"<%s>",(void)0) - -#endif -- cgit v1.2.3 From 140bbced6f270d9baf3df3b725932ecbbd5a4577 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Mon, 11 Dec 2017 19:45:57 +0200 Subject: lib/upytesthelper: MicroPython test helper layer on top of tinytest. Tinytest is classical assert-style framework, but MicroPython tests work in different way - they produce content, and that content should be matched against expected one to see if test passes. upytesthelper exactly adds helper functions to make that possible. --- lib/upytesthelper/upytesthelper.c | 126 ++++++++++++++++++++++++++++++++++++++ lib/upytesthelper/upytesthelper.h | 37 +++++++++++ 2 files changed, 163 insertions(+) create mode 100644 lib/upytesthelper/upytesthelper.c create mode 100644 lib/upytesthelper/upytesthelper.h (limited to 'lib') diff --git a/lib/upytesthelper/upytesthelper.c b/lib/upytesthelper/upytesthelper.c new file mode 100644 index 000000000..d28c5b9cc --- /dev/null +++ b/lib/upytesthelper/upytesthelper.c @@ -0,0 +1,126 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Linaro Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include + +#include "py/mphal.h" +#include "py/gc.h" +#include "py/runtime.h" +#include "py/compile.h" +#include "upytesthelper.h" + +static const char *test_exp_output; +static int test_exp_output_len, test_rem_output_len; +static int test_failed; +static void *heap_start, *heap_end; + +void upytest_set_heap(void *start, void *end) { + heap_start = start; + heap_end = end; +} + +void upytest_set_expected_output(const char *output, unsigned len) { + test_exp_output = output; + test_exp_output_len = test_rem_output_len = len; + test_failed = false; +} + +bool upytest_is_failed(void) { + if (test_failed) { + return true; + } + #if 0 + if (test_rem_output_len != 0) { + printf("remaining len: %d\n", test_rem_output_len); + } + #endif + return test_rem_output_len != 0; +} + +// MP_PLAT_PRINT_STRN() should be redirected to this function. +// It will pass-thru any content to mp_hal_stdout_tx_strn_cooked() +// (the dfault value of MP_PLAT_PRINT_STRN), but will also match +// it to the expected output as set by upytest_set_expected_output(). +// If mismatch happens, upytest_is_failed() returns true. +void upytest_output(const char *str, mp_uint_t len) { + if (!test_failed) { + if (len > test_rem_output_len) { + test_failed = true; + } else { + test_failed = memcmp(test_exp_output, str, len); + #if 0 + if (test_failed) { + printf("failed after char %u, within %d chars, res: %d\n", + test_exp_output_len - test_rem_output_len, (int)len, test_failed); + for (int i = 0; i < len; i++) { + if (str[i] != test_exp_output[i]) { + printf("%d %02x %02x\n", i, str[i], test_exp_output[i]); + } + } + } + #endif + test_exp_output += len; + test_rem_output_len -= len; + } + } + mp_hal_stdout_tx_strn_cooked(str, len); +} + +void upytest_execute_test(const char *src) { + // To provide clean room for each test, interpreter and heap are + // reinitialized before running each. + gc_init(heap_start, heap_end); + mp_init(); + mp_obj_list_init(mp_sys_path, 0); + mp_obj_list_init(mp_sys_argv, 0); + + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0); + qstr source_name = lex->source_name; + mp_parse_tree_t parse_tree = mp_parse(lex, MP_PARSE_FILE_INPUT); + mp_obj_t module_fun = mp_compile(&parse_tree, source_name, MP_EMIT_OPT_NONE, false); + mp_call_function_0(module_fun); + nlr_pop(); + } else { + mp_obj_t exc = (mp_obj_t)nlr.ret_val; + if (mp_obj_is_subclass_fast(mp_obj_get_type(exc), &mp_type_SystemExit)) { + // Assume that sys.exit() is called to skip the test. + // TODO: That can be always true, we should set up convention to + // use specific exit code as skip indicator. + tinytest_set_test_skipped_(); + goto end; + } + mp_obj_print_exception(&mp_plat_print, exc); + tt_abort_msg("Uncaught exception\n"); + } + + if (upytest_is_failed()) { + tinytest_set_test_failed_(); + } + +end: + mp_deinit(); +} diff --git a/lib/upytesthelper/upytesthelper.h b/lib/upytesthelper/upytesthelper.h new file mode 100644 index 000000000..3a292befd --- /dev/null +++ b/lib/upytesthelper/upytesthelper.h @@ -0,0 +1,37 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 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/mpconfig.h" +#include "lib/tinytest/tinytest.h" +#include "lib/tinytest/tinytest_macros.h" + +void upytest_set_heap(void *start, void *end); +void upytest_set_expected_output(const char *output, unsigned len); +void upytest_execute_test(const char *src); +void upytest_output(const char *str, mp_uint_t len); +bool upytest_is_failed(void); -- cgit v1.2.3 From f4ed2dfa942339dc1f174e8a83ff0d41073f1972 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Fri, 15 Dec 2017 19:41:08 +0200 Subject: lib/tinytest: Clean up test reporting in the presence of stdout output. tinytest is written with the idea that tests won't write to stdout, so it prints test name witjout newline, then executes test, then writes status. But MicroPython tests write to stdout, so the test output becomes a mess. So, instead print it like: # starting basics/andor.py ... test output ... basics/andor.py: OK --- lib/tinytest/tinytest.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/tinytest/tinytest.c b/lib/tinytest/tinytest.c index 1ef957d31..01772f3f8 100644 --- a/lib/tinytest/tinytest.c +++ b/lib/tinytest/tinytest.c @@ -234,8 +234,9 @@ testcase_run_one(const struct testgroup_t *group, return SKIP; } + printf("# starting %s%s\n", group->prefix, testcase->name); if (opt_verbosity>0 && !opt_forked) { - printf("%s%s: ", group->prefix, testcase->name); + //printf("%s%s: ", group->prefix, testcase->name); } else { if (opt_verbosity==0) printf("."); cur_test_prefix = group->prefix; @@ -252,6 +253,7 @@ testcase_run_one(const struct testgroup_t *group, outcome = testcase_run_bare_(testcase); } + printf("%s%s: ", group->prefix, testcase->name); if (outcome == OK) { ++n_ok; if (opt_verbosity>0 && !opt_forked) @@ -263,7 +265,8 @@ testcase_run_one(const struct testgroup_t *group, } else { ++n_bad; if (!opt_forked) - printf("\n [%s FAILED]\n", testcase->name); + //printf("\n [%s FAILED]\n", testcase->name); + puts("FAILED"); } if (opt_forked) { -- cgit v1.2.3 From 925c5b1da2fed80774dd393d597392a2c254effa Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 31 Jan 2018 18:21:07 +1100 Subject: lib/utils/pyexec.h: Include py/obj.h because its decls are needed. --- lib/utils/pyexec.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib') diff --git a/lib/utils/pyexec.h b/lib/utils/pyexec.h index bc98ba94a..678c56cf4 100644 --- a/lib/utils/pyexec.h +++ b/lib/utils/pyexec.h @@ -26,6 +26,8 @@ #ifndef MICROPY_INCLUDED_LIB_UTILS_PYEXEC_H #define MICROPY_INCLUDED_LIB_UTILS_PYEXEC_H +#include "py/obj.h" + typedef enum { PYEXEC_MODE_RAW_REPL, PYEXEC_MODE_FRIENDLY_REPL, -- cgit v1.2.3 From d9b9fbc41ae202cf9426cc1ae7514d230cc5c8d0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 13 Feb 2018 18:56:12 +1100 Subject: lib/utils/pyexec: Update to work with new MICROPY_HW_ENABLE_USB option. --- lib/utils/pyexec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/utils/pyexec.c b/lib/utils/pyexec.c index 1e99aa649..0522de797 100644 --- a/lib/utils/pyexec.c +++ b/lib/utils/pyexec.c @@ -35,7 +35,7 @@ #include "py/gc.h" #include "py/frozenmod.h" #include "py/mphal.h" -#if defined(USE_DEVICE_MODE) +#if MICROPY_HW_ENABLE_USB #include "irq.h" #include "usb.h" #endif @@ -406,7 +406,7 @@ friendly_repl_reset: for (;;) { input_restart: - #if defined(USE_DEVICE_MODE) + #if MICROPY_HW_ENABLE_USB if (usb_vcp_is_enabled()) { // If the user gets to here and interrupts are disabled then // they'll never see the prompt, traceback etc. The USB REPL needs -- cgit v1.2.3 From e22ef277b89389ed0a3e4317081b5e913aacdd98 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 9 Mar 2018 14:31:34 +1100 Subject: lib/stm32lib: Update library to include support for STM32H7 MCUs. Now points to the branch: work-F4-1.16.0+F7-1.7.0+H7-1.2.0+L4-1.8.1 --- lib/stm32lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/stm32lib b/lib/stm32lib index d2bcfda54..000df50c2 160000 --- a/lib/stm32lib +++ b/lib/stm32lib @@ -1 +1 @@ -Subproject commit d2bcfda543d3b99361e44112aca929225bdcc07f +Subproject commit 000df50c233083c7bea05d1fed6fa191a65694bb -- cgit v1.2.3 From 23f07b77e55664602354d49fdc6a16032768f293 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sun, 25 Mar 2018 23:58:56 +1100 Subject: lib/stm32lib: Update library for fix to H7 SPI strict aliasing error. --- lib/stm32lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/stm32lib b/lib/stm32lib index 000df50c2..90b996196 160000 --- a/lib/stm32lib +++ b/lib/stm32lib @@ -1 +1 @@ -Subproject commit 000df50c233083c7bea05d1fed6fa191a65694bb +Subproject commit 90b9961963b625db0f2aabfe8e5e508b1f4fb7f1 -- cgit v1.2.3 From 7d7b9cd5dffdecf1e4176a7f3ddb84e7e3bc7318 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 17 May 2018 13:11:31 +1000 Subject: lib/lwip: Update lwIP to v2.0.3, tag STABLE-2_0_3_RELEASE. --- lib/lwip | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/lwip b/lib/lwip index 5b8b5d459..92f23d6ca 160000 --- a/lib/lwip +++ b/lib/lwip @@ -1 +1 @@ -Subproject commit 5b8b5d459e7dd890724515bbfad86c705234f9ec +Subproject commit 92f23d6ca0971a32f2085b9480e738d34174417b -- cgit v1.2.3 From 191e2cf90a948fd579b93de9a32800e82e1efcc0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 28 May 2018 21:44:42 +1000 Subject: lib/stm32lib: Update library to include support for STM32F0 MCUs. Now points to branch: work-F0-1.9.0+F4-1.16.0+F7-1.7.0+H7-1.2.0+L4-1.8.1 --- lib/stm32lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/stm32lib b/lib/stm32lib index 90b996196..1fe30d144 160000 --- a/lib/stm32lib +++ b/lib/stm32lib @@ -1 +1 @@ -Subproject commit 90b9961963b625db0f2aabfe8e5e508b1f4fb7f1 +Subproject commit 1fe30d1446f2eba3730dc4b05e9ac0cf03bcf9bf -- cgit v1.2.3 From bc760dd34100099c352a0f185ec54ceae23d036d Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 23 Jul 2018 21:34:25 -0400 Subject: WIP: complete manual inspection of all significant changes --- docs/library/array.rst | 6 +- docs/library/ujson.rst | 8 +- docs/library/ure.rst | 1 - docs/reference/packages.rst | 312 --------------------------------- extmod/lwip-include/lwipopts.h | 2 +- extmod/modlwip.c | 8 +- extmod/moduhashlib.c | 16 +- extmod/vfs_fat.h | 8 +- extmod/vfs_fat_diskio.c | 193 +++++++------------- lib/axtls | 2 +- lib/mp-readline/readline.h | 2 - ports/esp8266/Makefile | 6 +- ports/esp8266/common-hal/busio/UART.c | 2 +- ports/esp8266/common-hal/os/__init__.c | 15 +- ports/esp8266/esp_mphal.c | 2 +- ports/esp8266/espneopixel.c | 19 +- ports/esp8266/espneopixel.h | 2 +- ports/esp8266/espuart.c | 309 -------------------------------- ports/esp8266/espuart.h | 106 ----------- ports/esp8266/etshal.h | 8 + ports/esp8266/machine_uart.c | 2 +- ports/esp8266/main.c | 19 -- ports/esp8266/modesp.c | 2 +- ports/esp8266/modnetwork.c | 4 +- ports/esp8266/modules/inisetup.py | 2 - ports/esp8266/modules/webrepl_setup.py | 10 ++ ports/esp8266/modutime.c | 12 +- ports/esp8266/mpconfigport.h | 2 +- ports/esp8266/uart.c | 309 ++++++++++++++++++++++++++++++++ ports/esp8266/uart.h | 106 +++++++++++ ports/nrf/mpconfigport.h | 4 - py/asmx86.h | 2 +- py/moduerrno.c | 1 + shared-module/os/__init__.c | 5 +- 34 files changed, 565 insertions(+), 942 deletions(-) delete mode 100644 docs/reference/packages.rst delete mode 100644 ports/esp8266/espuart.c delete mode 100644 ports/esp8266/espuart.h create mode 100644 ports/esp8266/uart.c create mode 100644 ports/esp8266/uart.h (limited to 'lib') diff --git a/docs/library/array.rst b/docs/library/array.rst index 859b370ea..d0121cb3e 100644 --- a/docs/library/array.rst +++ b/docs/library/array.rst @@ -16,14 +16,14 @@ Classes .. class:: array.array(typecode, [iterable]) Create array with elements of given type. Initial contents of the - array are given by *iterable*. If it is not provided, an empty + array are given by an `iterable`. If it is not provided, an empty array is created. .. method:: append(val) - Append new element *val* to the end of array, growing it. + Append new element ``val`` to the end of array, growing it. .. method:: extend(iterable) - Append new elements as contained in *iterable* to the end of + Append new elements as contained in `iterable` to the end of array, growing it. diff --git a/docs/library/ujson.rst b/docs/library/ujson.rst index ef9c70c25..4ed91f053 100644 --- a/docs/library/ujson.rst +++ b/docs/library/ujson.rst @@ -16,20 +16,20 @@ Functions .. function:: dump(obj, stream) - Serialise *obj* to a JSON string, writing it to the given *stream*. + Serialise ``obj`` to a JSON string, writing it to the given *stream*. .. function:: dumps(obj) - Return *obj* represented as a JSON string. + Return ``obj`` represented as a JSON string. .. function:: load(stream) - Parse the given *stream*, interpreting it as a JSON string and + Parse the given ``stream``, interpreting it as a JSON string and deserialising the data to a Python object. The resulting object is returned. Parsing continues until end-of-file is encountered. - A :exc:`ValueError` is raised if the data in *stream* is not correctly formed. + A :exc:`ValueError` is raised if the data in ``stream`` is not correctly formed. .. function:: loads(str) diff --git a/docs/library/ure.rst b/docs/library/ure.rst index 2447de121..4af182b01 100644 --- a/docs/library/ure.rst +++ b/docs/library/ure.rst @@ -69,7 +69,6 @@ Functions .. data:: DEBUG Flag value, display debug information about compiled expression. - (Availability depends on `MicroPython port`.) .. _regex: diff --git a/docs/reference/packages.rst b/docs/reference/packages.rst deleted file mode 100644 index 8be2461c2..000000000 --- a/docs/reference/packages.rst +++ /dev/null @@ -1,312 +0,0 @@ -Distribution packages, package management, and deploying applications -===================================================================== - -Just as the "big" Python, MicroPython supports creation of "third party" -packages, distributing them, and easily installing them in each user's -environment. This chapter discusses how these actions are achieved. -Some familiarity with Python packaging is recommended. - -Overview --------- - -Steps below represent a high-level workflow when creating and consuming -packages: - -1. Python modules and packages are turned into distribution package - archives, and published at the Python Package Index (PyPI). -2. `upip` package manager can be used to install a distribution package - on a `MicroPython port` with networking capabilities (for example, - on the Unix port). -3. For ports without networking capabilities, an "installation image" - can be prepared on the Unix port, and transferred to a device by - suitable means. -4. For low-memory ports, the installation image can be frozen as the - bytecode into MicroPython executable, thus minimizing the memory - storage overheads. - -The sections below describe this process in details. - -Distribution packages ---------------------- - -Python modules and packages can be packaged into archives suitable for -transfer between systems, storing at the well-known location (PyPI), -and downloading on demand for deployment. These archives are known as -*distribution packages* (to differentiate them from Python packages -(means to organize Python source code)). - -The MicroPython distribution package format is a well-known tar.gz -format, with some adaptations however. The Gzip compressor, used as -an external wrapper for TAR archives, by default uses 32KB dictionary -size, which means that to uncompress a compressed stream, 32KB of -contguous memory needs to be allocated. This requirement may be not -satisfiable on low-memory devices, which may have total memory available -less than that amount, and even if not, a contiguous block like that -may be hard to allocate due to memory fragmentation. To accommodate -these constraints, MicroPython distribution packages use Gzip compression -with the dictionary size of 4K, which should be a suitable compromise -with still achieving some compression while being able to uncompressed -even by the smallest devices. - -Besides the small compression dictionary size, MicroPython distribution -packages also have other optimizations, like removing any files from -the archive which aren't used by the installation process. In particular, -`upip` package manager doesn't execute ``setup.py`` during installation -(see below), and thus that file is not included in the archive. - -At the same time, these optimizations make MicroPython distribution -packages not compatible with `CPython`'s package manager, ``pip``. -This isn't considered a big problem, because: - -1. Packages can be installed with `upip`, and then can be used with - CPython (if they are compatible with it). -2. In the other direction, majority of CPython packages would be - incompatible with MicroPython by various reasons, first of all, - the reliance on features not implemented by MicroPython. - -Summing up, the MicroPython distribution package archives are highly -optimized for MicroPython's target environments, which are highly -resource constrained devices. - - -``upip`` package manager ------------------------- - -MicroPython distribution packages are intended to be installed using -the `upip` package manager. `upip` is a Python application which is -usually distributed (as frozen bytecode) with network-enabled -`MicroPython ports `. At the very least, -`upip` is available in the `MicroPython Unix port`. - -On any `MicroPython port` providing `upip`, it can be accessed as -following:: - - import upip - upip.help() - upip.install(package_or_package_list, [path]) - -Where *package_or_package_list* is the name of a distribution -package to install, or a list of such names to install multiple -packages. Optional *path* parameter specifies filesystem -location to install under and defaults to the standard library -location (see below). - -An example of installing a specific package and then using it:: - - >>> import upip - >>> upip.install("micropython-pystone_lowmem") - [...] - >>> import pystone_lowmem - >>> pystone_lowmem.main() - -Note that the name of Python package and the name of distribution -package for it in general don't have to match, and oftentimes they -don't. This is because PyPI provides a central package repository -for all different Python implementations and versions, and thus -distribution package names may need to be namespaced for a particular -implementation. For example, all packages from `micropython-lib` -follow this naming convention: for a Python module or package named -``foo``, the distribution package name is ``micropython-foo``. - -For the ports which run MicroPython executable from the OS command -prompts (like the Unix port), `upip` can be (and indeed, usually is) -run from the command line instead of MicroPython's own REPL. The -commands which corresponds to the example above are:: - - micropython -m upip -h - micropython -m upip install [-p ] ... - micropython -m upip install micropython-pystone_lowmem - -[TODO: Describe installation path.] - - -Cross-installing packages -------------------------- - -For `MicroPython ports ` without native networking -capabilities, the recommend process is "cross-installing" them into a -"directory image" using the `MicroPython Unix port`, and then -transferring this image to a device by suitable means. - -Installing to a directory image involves using ``-p`` switch to `upip`:: - - micropython -m upip install -p install_dir micropython-pystone_lowmem - -After this command, the package content (and contents of every depenency -packages) will be available in the ``install_dir/`` subdirectory. You -would need to transfer contents of this directory (without the -``install_dir/`` prefix) to the device, at the suitable location, where -it can be found by the Python ``import`` statement (see discussion of -the `upip` installation path above). - - -Cross-installing packages with freezing ---------------------------------------- - -For the low-memory `MicroPython ports `, the process -described in the previous section does not provide the most efficient -resource usage,because the packages are installed in the source form, -so need to be compiled to the bytecome on each import. This compilation -requires RAM, and the resulting bytecode is also stored in RAM, reducing -its amount available for storing application data. Moreover, the process -above requires presence of the filesystem on a device, and the most -resource-constrained devices may not even have it. - -The bytecode freezing is a process which resolves all the issues -mentioned above: - -* The source code is pre-compiled into bytecode and store as such. -* The bytecode is stored in ROM, not RAM. -* Filesystem is not required for frozen packages. - -Using frozen bytecode requires building the executable (firmware) -for a given `MicroPython port` from the C source code. Consequently, -the process is: - -1. Follow the instructions for a particular port on setting up a - toolchain and building the port. For example, for ESP8266 port, - study instructions in ``ports/esp8266/README.md`` and follow them. - Make sure you can build the port and deploy the resulting - executable/firmware successfully before proceeding to the next steps. -2. Build `MicroPython Unix port` and make sure it is in your PATH and - you can execute ``micropython``. -3. Change to port's directory (e.g. ``ports/esp8266/`` for ESP8266). -4. Run ``make clean-frozen``. This step cleans up any previous - modules which were installed for freezing (consequently, you need - to skip this step to add additional modules, instead of starting - from scratch). -5. Run ``micropython -m upip install -p modules ...`` to - install packages you want to freeze. -6. Run ``make clean``. -7. Run ``make``. - -After this, you should have the executable/firmware with modules as -the bytecode inside, which you can deploy the usual way. - -Few notes: - -1. Step 5 in the sequence above assumes that the distribution package - is available from PyPI. If that is not the case, you would need - to copy Python source files manually to ``modules/`` subdirectory - of the port port directory. (Note that upip does not support - installing from e.g. version control repositories). -2. The firmware for baremetal devices usually has size restrictions, - so adding too many frozen modules may overflow it. Usually, you - would get a linking error if this happens. However, in some cases, - an image may be produced, which is not runnable on a device. Such - cases are in general bugs, and should be reported and further - investigated. If you face such a situation, as an initial step, - you may want to decrease the amount of frozen modules included. - - -Creating distribution packages ------------------------------- - -Distribution packages for MicroPython are created in the same manner -as for CPython or any other Python implementation, see references at -the end of chapter. Setuptools (instead of distutils) should be used, -because distutils do not support dependencies and other features. "Source -distribution" (``sdist``) format is used for packaging. The post-processing -discussed above, (and pre-processing discussed in the following section) -is achieved by using custom ``sdist`` command for setuptools. Thus, packaging -steps remain the same as for the standard setuptools, the user just -needs to override ``sdist`` command implementation by passing the -appropriate argument to ``setup()`` call:: - - from setuptools import setup - import sdist_upip - - setup( - ..., - cmdclass={'sdist': sdist_upip.sdist} - ) - -The sdist_upip.py module as referenced above can be found in -`micropython-lib`: -https://github.com/micropython/micropython-lib/blob/master/sdist_upip.py - - -Application resources ---------------------- - -A complete application, besides the source code, oftentimes also consists -of data files, e.g. web page templates, game images, etc. It's clear how -to deal with those when application is installed manually - you just put -those data files in the filesystem at some location and use the normal -file access functions. - -The situation is different when deploying applications from packages - this -is more advanced, streamlined and flexible way, but also requires more -advanced approach to accessing data files. This approach is treating -the data files as "resources", and abstracting away access to them. - -Python supports resource access using its "setuptools" library, using -``pkg_resources`` module. MicroPython, following its usual approach, -implements subset of the functionality of that module, specifically -``pkg_resources.resource_stream(package, resource)`` function. -The idea is that an application calls this function, passing a -resource identifier, which is a relative path to data file within -the specified package (usually top-level application package). It -returns a stream object which can be used to access resource contents. -Thus, the ``resource_stream()`` emulates interface of the standard -`open()` function. - -Implementation-wise, ``resource_stream()`` uses file operations -underlyingly, if distribution package is install in the filesystem. -However, it also supports functioning without the underlying filesystem, -e.g. if the package is frozen as the bytecode. This however requires -an extra intermediate step when packaging application - creation of -"Python resource module". - -The idea of this module is to convert binary data to a Python bytes -object, and put it into the dictionary, indexed by the resource name. -This conversion is done automatically using overridden ``sdist`` command -described in the previous section. - -Let's trace the complete process using the following example. Suppose -your application has the following structure:: - - my_app/ - __main__.py - utils.py - data/ - page.html - image.png - -``__main__.py`` and ``utils.py`` should access resources using the -following calls:: - - import pkg_resources - - pkg_resources.resource_stream(__name__, "data/page.html") - pkg_resources.resource_stream(__name__, "data/image.png") - -You can develop and debug using the `MicroPython Unix port` as usual. -When time comes to make a distribution package out of it, just use -overridden "sdist" command from sdist_upip.py module as described in -the previous section. - -This will create a Python resource module named ``R.py``, based on the -files declared in ``MANIFEST`` or ``MANIFEST.in`` files (any non-``.py`` -file will be considered a resource and added to ``R.py``) - before -proceeding with the normal packaging steps. - -Prepared like this, your application will work both when deployed to -filesystem and as frozen bytecode. - -If you would like to debug ``R.py`` creation, you can run:: - - python3 setup.py sdist --manifest-only - -Alternatively, you can use tools/mpy_bin2res.py script from the -MicroPython distribution, in which can you will need to pass paths -to all resource files:: - - mpy_bin2res.py data/page.html data/image.png - -References ----------- - -* Python Packaging User Guide: https://packaging.python.org/ -* Setuptools documentation: https://setuptools.readthedocs.io/ -* Distutils documentation: https://docs.python.org/3/library/distutils.html diff --git a/extmod/lwip-include/lwipopts.h b/extmod/lwip-include/lwipopts.h index 2122f30f0..805bec223 100644 --- a/extmod/lwip-include/lwipopts.h +++ b/extmod/lwip-include/lwipopts.h @@ -23,7 +23,7 @@ typedef uint32_t sys_prot_t; #define LWIP_NETCONN 0 #define LWIP_SOCKET 0 -#ifdef MICROPY_PY_LWIP_SLIP +#if MICROPY_PY_LWIP_SLIP #define LWIP_HAVE_SLIPIF 1 #endif diff --git a/extmod/modlwip.c b/extmod/modlwip.c index dfb5de9e4..e5e92c42b 100644 --- a/extmod/modlwip.c +++ b/extmod/modlwip.c @@ -69,12 +69,12 @@ #define ip_reset_option(pcb, opt) ((pcb)->so_options &= ~(opt)) #endif -#ifdef MICROPY_PY_LWIP_SLIP +#if MICROPY_PY_LWIP_SLIP #include "netif/slipif.h" #include "lwip/sio.h" #endif -#ifdef MICROPY_PY_LWIP_SLIP +#if MICROPY_PY_LWIP_SLIP /******************************************************************************/ // Slip object for modlwip. Requires a serial driver for the port that supports // the lwip serial callback functions. @@ -1419,7 +1419,7 @@ STATIC mp_obj_t lwip_print_pcbs() { } MP_DEFINE_CONST_FUN_OBJ_0(lwip_print_pcbs_obj, lwip_print_pcbs); -#ifdef MICROPY_PY_LWIP +#if MICROPY_PY_LWIP STATIC const mp_rom_map_elem_t mp_module_lwip_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_lwip) }, @@ -1429,7 +1429,7 @@ STATIC const mp_rom_map_elem_t mp_module_lwip_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_print_pcbs), MP_ROM_PTR(&lwip_print_pcbs_obj) }, // objects { MP_ROM_QSTR(MP_QSTR_socket), MP_ROM_PTR(&lwip_socket_type) }, -#ifdef MICROPY_PY_LWIP_SLIP +#if MICROPY_PY_LWIP_SLIP { MP_ROM_QSTR(MP_QSTR_slip), MP_ROM_PTR(&lwip_slip_type) }, #endif // class constants diff --git a/extmod/moduhashlib.c b/extmod/moduhashlib.c index d062271bb..6389455c0 100644 --- a/extmod/moduhashlib.c +++ b/extmod/moduhashlib.c @@ -29,6 +29,14 @@ #include "py/runtime.h" +static void check_not_unicode(const mp_obj_t arg) { +#if MICROPY_CPYTHON_COMPAT + if (MP_OBJ_IS_STR(arg)) { + mp_raise_TypeError("a bytes-like object is required"); + } +#endif +} + #if MICROPY_PY_UHASHLIB #if MICROPY_PY_UHASHLIB_SHA256 @@ -47,20 +55,12 @@ #include "lib/axtls/crypto/crypto.h" #endif -static void check_not_unicode(const mp_obj_t arg) { -#if MICROPY_CPYTHON_COMPAT - if (MP_OBJ_IS_STR(arg)) { - mp_raise_TypeError("a bytes-like object is required"); - } -#endif - #if MICROPY_SSL_MBEDTLS #include "mbedtls/sha1.h" #endif #endif -} typedef struct _mp_obj_hash_t { mp_obj_base_t base; diff --git a/extmod/vfs_fat.h b/extmod/vfs_fat.h index 3f46c278f..ded8bc885 100644 --- a/extmod/vfs_fat.h +++ b/extmod/vfs_fat.h @@ -63,11 +63,11 @@ typedef struct _pyb_file_obj_t { // These should be general types (mpy TOOD says so). In micropython, these are defined in // mpconfigport.h. -#define mp_type_fileio mp_type_vfs_fat_fileio -#define mp_type_textio mp_type_vfs_fat_textio +////////////#define mp_type_fileio mp_type_vfs_fat_fileio +////////////#define mp_type_textio mp_type_vfs_fat_textio -extern const mp_obj_type_t mp_type_fileio; -extern const mp_obj_type_t mp_type_textio; +////////////extern const mp_obj_type_t mp_type_fileio; +////////////extern const mp_obj_type_t mp_type_textio; extern const byte fresult_to_errno_table[20]; extern const mp_obj_type_t mp_fat_vfs_type; diff --git a/extmod/vfs_fat_diskio.c b/extmod/vfs_fat_diskio.c index 95ef77895..3b5c7d888 100644 --- a/extmod/vfs_fat_diskio.c +++ b/extmod/vfs_fat_diskio.c @@ -36,6 +36,8 @@ #include "py/mphal.h" #include "py/runtime.h" +#include "py/binary.h" +#include "py/objarray.h" #include "lib/oofatfs/ff.h" #include "lib/oofatfs/diskio.h" #include "extmod/vfs_fat.h" @@ -51,62 +53,6 @@ STATIC fs_user_mount_t *disk_get_device(void *bdev) { return (fs_user_mount_t*)bdev; } -/*-----------------------------------------------------------------------*/ -/* Initialize a Drive */ -/*-----------------------------------------------------------------------*/ - -STATIC -DSTATUS disk_initialize ( - bdev_t pdrv /* Physical drive number (0..) */ -) -{ - fs_user_mount_t *vfs = disk_get_device(pdrv); - if (vfs == NULL) { - return STA_NOINIT; - } - - if (vfs->flags & FSUSER_HAVE_IOCTL) { - // new protocol with ioctl; call ioctl(INIT, 0) - vfs->u.ioctl[2] = MP_OBJ_NEW_SMALL_INT(BP_IOCTL_INIT); - vfs->u.ioctl[3] = MP_OBJ_NEW_SMALL_INT(0); // unused - mp_obj_t ret = mp_call_method_n_kw(2, 0, vfs->u.ioctl); - if (ret != mp_const_none && MP_OBJ_SMALL_INT_VALUE(ret) != 0) { - // error initialising - return STA_NOINIT; - } - } - - if (vfs->writeblocks[0] == MP_OBJ_NULL) { - return STA_PROTECT; - } else { - return 0; - } -} - -/*-----------------------------------------------------------------------*/ -/* Get Disk Status */ -/*-----------------------------------------------------------------------*/ - -STATIC -DSTATUS disk_status ( - bdev_t pdrv /* Physical drive nmuber (0..) */ -) -{ - fs_user_mount_t *vfs = disk_get_device(pdrv); - if (vfs == NULL) { - return STA_NOINIT; - } - - // This is used to determine the writeability of the disk from MicroPython. - // So, if its USB writable we make it read-only from MicroPython. - if (vfs->writeblocks[0] == MP_OBJ_NULL || - (vfs->flags & FSUSER_USB_WRITABLE) != 0) { - return STA_PROTECT; - } else { - return 0; - } -} - /*-----------------------------------------------------------------------*/ /* Read Sector(s) */ /*-----------------------------------------------------------------------*/ @@ -208,54 +154,21 @@ DRESULT disk_ioctl ( return RES_PARERR; } + // First part: call the relevant method of the underlying block device + mp_obj_t ret = mp_const_none; if (vfs->flags & FSUSER_HAVE_IOCTL) { // new protocol with ioctl - switch (cmd) { - case CTRL_SYNC: - vfs->u.ioctl[2] = MP_OBJ_NEW_SMALL_INT(BP_IOCTL_SYNC); - vfs->u.ioctl[3] = MP_OBJ_NEW_SMALL_INT(0); // unused - mp_call_method_n_kw(2, 0, vfs->u.ioctl); - return RES_OK; - - case GET_SECTOR_COUNT: { - vfs->u.ioctl[2] = MP_OBJ_NEW_SMALL_INT(BP_IOCTL_SEC_COUNT); - vfs->u.ioctl[3] = MP_OBJ_NEW_SMALL_INT(0); // unused - mp_obj_t ret = mp_call_method_n_kw(2, 0, vfs->u.ioctl); - *((DWORD*)buff) = mp_obj_get_int(ret); - return RES_OK; - } - - case GET_SECTOR_SIZE: { - vfs->u.ioctl[2] = MP_OBJ_NEW_SMALL_INT(BP_IOCTL_SEC_SIZE); - vfs->u.ioctl[3] = MP_OBJ_NEW_SMALL_INT(0); // unused - mp_obj_t ret = mp_call_method_n_kw(2, 0, vfs->u.ioctl); - if (ret == mp_const_none) { - // Default sector size - *((WORD*)buff) = 512; - } else { - *((WORD*)buff) = mp_obj_get_int(ret); - } - #if _MAX_SS != _MIN_SS - // need to store ssize because we use it in disk_read/disk_write - vfs->fatfs.ssize = *((WORD*)buff); - #endif - return RES_OK; - } - - case GET_BLOCK_SIZE: - *((DWORD*)buff) = 1; // erase block size in units of sector size - return RES_OK; - - case IOCTL_INIT: - *((DSTATUS*)buff) = disk_initialize(pdrv); - return RES_OK; - - case IOCTL_STATUS: - *((DSTATUS*)buff) = disk_status(pdrv); - return RES_OK; - - default: - return RES_PARERR; + static const uint8_t op_map[8] = { + [CTRL_SYNC] = BP_IOCTL_SYNC, + [GET_SECTOR_COUNT] = BP_IOCTL_SEC_COUNT, + [GET_SECTOR_SIZE] = BP_IOCTL_SEC_SIZE, + [IOCTL_INIT] = BP_IOCTL_INIT, + }; + uint8_t bp_op = op_map[cmd & 7]; + if (bp_op != 0) { + vfs->u.ioctl[2] = MP_OBJ_NEW_SMALL_INT(bp_op); + vfs->u.ioctl[3] = MP_OBJ_NEW_SMALL_INT(0); // unused + ret = mp_call_method_n_kw(2, 0, vfs->u.ioctl); } } else { // old protocol with sync and count @@ -264,37 +177,67 @@ DRESULT disk_ioctl ( if (vfs->u.old.sync[0] != MP_OBJ_NULL) { mp_call_method_n_kw(0, 0, vfs->u.old.sync); } - return RES_OK; + break; - case GET_SECTOR_COUNT: { - mp_obj_t ret = mp_call_method_n_kw(0, 0, vfs->u.old.count); - *((DWORD*)buff) = mp_obj_get_int(ret); - return RES_OK; - } + case GET_SECTOR_COUNT: + ret = mp_call_method_n_kw(0, 0, vfs->u.old.count); + break; case GET_SECTOR_SIZE: - *((WORD*)buff) = 512; // old protocol had fixed sector size - #if _MAX_SS != _MIN_SS - // need to store ssize because we use it in disk_read/disk_write - vfs->fatfs.ssize = 512; - #endif - return RES_OK; - - case GET_BLOCK_SIZE: - *((DWORD*)buff) = 1; // erase block size in units of sector size - return RES_OK; + // old protocol has fixed sector size of 512 bytes + break; case IOCTL_INIT: - *((DSTATUS*)buff) = disk_initialize(pdrv); - return RES_OK; + // old protocol doesn't have init + break; + } + } + + // Second part: convert the result for return + switch (cmd) { + case CTRL_SYNC: + return RES_OK; + + case GET_SECTOR_COUNT: { + *((DWORD*)buff) = mp_obj_get_int(ret); + return RES_OK; + } + + case GET_SECTOR_SIZE: { + if (ret == mp_const_none) { + // Default sector size + *((WORD*)buff) = 512; + } else { + *((WORD*)buff) = mp_obj_get_int(ret); + } + #if _MAX_SS != _MIN_SS + // need to store ssize because we use it in disk_read/disk_write + vfs->fatfs.ssize = *((WORD*)buff); + #endif + return RES_OK; + } - case IOCTL_STATUS: - *((DSTATUS*)buff) = disk_status(pdrv); - return RES_OK; + case GET_BLOCK_SIZE: + *((DWORD*)buff) = 1; // erase block size in units of sector size + return RES_OK; - default: - return RES_PARERR; + case IOCTL_INIT: + case IOCTL_STATUS: { + DSTATUS stat; + if (ret != mp_const_none && MP_OBJ_SMALL_INT_VALUE(ret) != 0) { + // error initialising + stat = STA_NOINIT; + } else if (vfs->writeblocks[0] == MP_OBJ_NULL) { + stat = STA_PROTECT; + } else { + stat = 0; + } + *((DSTATUS*)buff) = stat; + return RES_OK; } + + default: + return RES_PARERR; } } diff --git a/lib/axtls b/lib/axtls index dac9176ca..43a6e6bd3 160000 --- a/lib/axtls +++ b/lib/axtls @@ -1 +1 @@ -Subproject commit dac9176cac58cc5e49669a9a4d404a6f6dd7cc10 +Subproject commit 43a6e6bd3bbc03dc501e16b89fba0ef042ed3ea0 diff --git a/lib/mp-readline/readline.h b/lib/mp-readline/readline.h index 17d4ec60e..00aa9622a 100644 --- a/lib/mp-readline/readline.h +++ b/lib/mp-readline/readline.h @@ -26,8 +26,6 @@ #ifndef MICROPY_INCLUDED_LIB_MP_READLINE_READLINE_H #define MICROPY_INCLUDED_LIB_MP_READLINE_READLINE_H -#include "py/misc.h" - #define CHAR_CTRL_A (1) #define CHAR_CTRL_B (2) #define CHAR_CTRL_C (3) diff --git a/ports/esp8266/Makefile b/ports/esp8266/Makefile index 5c0983fe7..89e9be0c3 100644 --- a/ports/esp8266/Makefile +++ b/ports/esp8266/Makefile @@ -77,7 +77,7 @@ SRC_C = \ esp_init_data.c \ gccollect.c \ lexerstr32.c \ - espuart.c \ + uart.c \ esppwm.c \ espneopixel.c \ intr.c \ @@ -193,7 +193,10 @@ LIB_SRC_C += \ lib/oofatfs/option/unicode.c endif +DRIVERS_SRC_C = $(addprefix drivers/,\ bus/softspi.c \ + ) + SRC_S = \ gchelper.s \ @@ -206,6 +209,7 @@ OBJ += $(addprefix $(BUILD)/, $(SRC_SHARED_MODULE_EXPANDED:.c=.o)) 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)) # List of sources for qstr extraction SRC_QSTR += $(SRC_C) $(SRC_COMMON_HAL_EXPANDED) $(SRC_SHARED_MODULE_EXPANDED) $(STM_SRC_C) $(EXTMOD_SRC_C) $(DRIVERS_SRC_C) diff --git a/ports/esp8266/common-hal/busio/UART.c b/ports/esp8266/common-hal/busio/UART.c index 9b5d86ef5..5540e3573 100644 --- a/ports/esp8266/common-hal/busio/UART.c +++ b/ports/esp8266/common-hal/busio/UART.c @@ -29,7 +29,7 @@ #include "shared-bindings/busio/UART.h" #include "ets_sys.h" -#include "espuart.h" +#include "uart.h" #include "py/nlr.h" diff --git a/ports/esp8266/common-hal/os/__init__.c b/ports/esp8266/common-hal/os/__init__.c index b9773d186..a686964be 100644 --- a/ports/esp8266/common-hal/os/__init__.c +++ b/ports/esp8266/common-hal/os/__init__.c @@ -27,9 +27,11 @@ #include +#include "esp_mphal.h" #include "etshal.h" #include "py/objtuple.h" #include "py/objstr.h" +#include "extmod/misc.h" #include "genhdr/mpversion.h" #include "user_interface.h" @@ -75,19 +77,6 @@ bool common_hal_os_urandom(uint8_t* buffer, uint32_t length) { i++; new_random >>= 8; } -// We wrap the mp_uos_dupterm function to detect if a UART is attached or not -mp_obj_t os_dupterm(size_t n_args, const mp_obj_t *args) { - mp_obj_t prev_obj = mp_uos_dupterm_obj.fun.var(n_args, args); - if (mp_obj_get_type(args[0]) == &pyb_uart_type) { - ++uart_attached_to_dupterm; - } - if (mp_obj_get_type(prev_obj) == &pyb_uart_type) { - --uart_attached_to_dupterm; - } - return prev_obj; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(os_dupterm_obj, 1, 2, os_dupterm); - } return true; } diff --git a/ports/esp8266/esp_mphal.c b/ports/esp8266/esp_mphal.c index 5dcdd6fba..be284c8f3 100644 --- a/ports/esp8266/esp_mphal.c +++ b/ports/esp8266/esp_mphal.c @@ -27,7 +27,7 @@ #include #include "ets_sys.h" #include "etshal.h" -#include "espuart.h" +#include "uart.h" #include "esp_mphal.h" #include "user_interface.h" #include "ets_alt_task.h" diff --git a/ports/esp8266/espneopixel.c b/ports/esp8266/espneopixel.c index f3827283d..6c7659186 100644 --- a/ports/esp8266/espneopixel.c +++ b/ports/esp8266/espneopixel.c @@ -16,7 +16,7 @@ #define NEO_KHZ400 (1) -void /*ICACHE_RAM_ATTR*/ esp_neopixel_write(uint8_t pin, uint8_t *pixels, uint32_t numBytes) { +void /*ICACHE_RAM_ATTR*/ esp_neopixel_write(uint8_t pin, uint8_t *pixels, uint32_t numBytes, bool is800KHz) { uint8_t *p, *end, pix, mask; uint32_t t, time0, time1, period, c, startTime, pinMask; @@ -30,10 +30,19 @@ void /*ICACHE_RAM_ATTR*/ esp_neopixel_write(uint8_t pin, uint8_t *pixels, uint32 uint32_t fcpu = system_get_cpu_freq() * 1000000; - - time0 = fcpu / 2857143; // 0.35us - time1 = fcpu / 1250000; // 0.8us - period = fcpu / 800000; // 1.25us per bit +#ifdef NEO_KHZ400 + if(is800KHz) { +#endif + time0 = fcpu / 2857143; // 0.35us + time1 = fcpu / 1250000; // 0.8us + period = fcpu / 800000; // 1.25us per bit +#ifdef NEO_KHZ400 + } else { // 400 KHz bitstream + time0 = fcpu / 2000000; // 0.5uS + time1 = fcpu / 833333; // 1.2us + period = fcpu / 400000; // 2.5us per bit + } +#endif uint32_t irq_state = mp_hal_quiet_timing_enter(); for(t = time0;; t = time0) { diff --git a/ports/esp8266/espneopixel.h b/ports/esp8266/espneopixel.h index 6743b3b97..c444740ff 100644 --- a/ports/esp8266/espneopixel.h +++ b/ports/esp8266/espneopixel.h @@ -1,6 +1,6 @@ #ifndef MICROPY_INCLUDED_ESP8266_ESPNEOPIXEL_H #define MICROPY_INCLUDED_ESP8266_ESPNEOPIXEL_H -void esp_neopixel_write(uint8_t pin, uint8_t *pixels, uint32_t numBytes); +void esp_neopixel_write(uint8_t pin, uint8_t *pixels, uint32_t numBytes, bool is800KHz); #endif // MICROPY_INCLUDED_ESP8266_ESPNEOPIXEL_H diff --git a/ports/esp8266/espuart.c b/ports/esp8266/espuart.c deleted file mode 100644 index 557b771a3..000000000 --- a/ports/esp8266/espuart.c +++ /dev/null @@ -1,309 +0,0 @@ -/****************************************************************************** - * Copyright 2013-2014 Espressif Systems (Wuxi) - * - * FileName: uart.c - * - * Description: Two UART mode configration and interrupt handler. - * Check your hardware connection while use this mode. - * - * Modification history: - * 2014/3/12, v1.0 create this file. -*******************************************************************************/ -#include "ets_sys.h" -#include "osapi.h" -#include "espuart.h" -#include "osapi.h" -#include "uart_register.h" -#include "etshal.h" -#include "c_types.h" -#include "user_interface.h" -#include "esp_mphal.h" - -// seems that this is missing in the Espressif SDK -#define FUNC_U0RXD 0 - -#define UART_REPL UART0 - -// UartDev is defined and initialized in rom code. -extern UartDevice UartDev; - -// the uart to which OS messages go; -1 to disable -static int uart_os = UART_OS; - -#if MICROPY_REPL_EVENT_DRIVEN -static os_event_t uart_evt_queue[16]; -#endif - -// A small, static ring buffer for incoming chars -// This will only be populated if the UART is not attached to dupterm -static byte uart_ringbuf_array[16]; -static ringbuf_t uart_ringbuf = {uart_ringbuf_array, sizeof(uart_ringbuf_array), 0, 0}; - -static void uart0_rx_intr_handler(void *para); - -void soft_reset(void); -void mp_keyboard_interrupt(void); - -/****************************************************************************** - * FunctionName : uart_config - * Description : Internal used function - * UART0 used for data TX/RX, RX buffer size is 0x100, interrupt enabled - * UART1 just used for debug output - * Parameters : uart_no, use UART0 or UART1 defined ahead - * Returns : NONE -*******************************************************************************/ -static void ICACHE_FLASH_ATTR uart_config(uint8 uart_no) { - if (uart_no == UART1) { - PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_U1TXD_BK); - } else { - ETS_UART_INTR_ATTACH(uart0_rx_intr_handler, NULL); - PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U); - PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD); - PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD); - } - - uart_div_modify(uart_no, UART_CLK_FREQ / (UartDev.baut_rate)); - - WRITE_PERI_REG(UART_CONF0(uart_no), UartDev.exist_parity - | UartDev.parity - | (UartDev.stop_bits << UART_STOP_BIT_NUM_S) - | (UartDev.data_bits << UART_BIT_NUM_S)); - - // clear rx and tx fifo,not ready - SET_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST); - CLEAR_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST); - - if (uart_no == UART0) { - // set rx fifo trigger - WRITE_PERI_REG(UART_CONF1(uart_no), - ((0x10 & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S) | - ((0x10 & UART_RX_FLOW_THRHD) << UART_RX_FLOW_THRHD_S) | - UART_RX_FLOW_EN | - (0x02 & UART_RX_TOUT_THRHD) << UART_RX_TOUT_THRHD_S | - UART_RX_TOUT_EN); - SET_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_TOUT_INT_ENA | - UART_FRM_ERR_INT_ENA); - } else { - WRITE_PERI_REG(UART_CONF1(uart_no), - ((UartDev.rcv_buff.TrigLvl & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S)); - } - - // clear all interrupt - WRITE_PERI_REG(UART_INT_CLR(uart_no), 0xffff); - // enable rx_interrupt - SET_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_FULL_INT_ENA); -} - -/****************************************************************************** - * FunctionName : uart1_tx_one_char - * Description : Internal used function - * Use uart1 interface to transfer one char - * Parameters : uint8 TxChar - character to tx - * Returns : OK -*******************************************************************************/ -void uart_tx_one_char(uint8 uart, uint8 TxChar) { - while (true) { - uint32 fifo_cnt = READ_PERI_REG(UART_STATUS(uart)) & (UART_TXFIFO_CNT<> UART_TXFIFO_CNT_S & UART_TXFIFO_CNT) < 126) { - break; - } - } - WRITE_PERI_REG(UART_FIFO(uart), TxChar); -} - -void uart_flush(uint8 uart) { - while (true) { - uint32 fifo_cnt = READ_PERI_REG(UART_STATUS(uart)) & (UART_TXFIFO_CNT<> UART_TXFIFO_CNT_S & UART_TXFIFO_CNT) == 0) { - break; - } - } -} - -/****************************************************************************** - * FunctionName : uart1_write_char - * Description : Internal used function - * Do some special deal while tx char is '\r' or '\n' - * Parameters : char c - character to tx - * Returns : NONE -*******************************************************************************/ -static void ICACHE_FLASH_ATTR -uart_os_write_char(char c) { - if (uart_os == -1) { - return; - } - if (c == '\n') { - uart_tx_one_char(uart_os, '\r'); - uart_tx_one_char(uart_os, '\n'); - } else if (c == '\r') { - } else { - uart_tx_one_char(uart_os, c); - } -} - -void ICACHE_FLASH_ATTR -uart_os_config(int uart) { - uart_os = uart; -} - -/****************************************************************************** - * FunctionName : uart0_rx_intr_handler - * Description : Internal used function - * UART0 interrupt handler, add self handle code inside - * Parameters : void *para - point to ETS_UART_INTR_ATTACH's arg - * Returns : NONE -*******************************************************************************/ - -static void uart0_rx_intr_handler(void *para) { - /* uart0 and uart1 intr combine togther, when interrupt occur, see reg 0x3ff20020, bit2, bit0 represents - * uart1 and uart0 respectively - */ - - uint8 uart_no = UART_REPL; - - if (UART_FRM_ERR_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_FRM_ERR_INT_ST)) { - // frame error - WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_FRM_ERR_INT_CLR); - } - - if (UART_RXFIFO_FULL_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_FULL_INT_ST)) { - // fifo full - goto read_chars; - } else if (UART_RXFIFO_TOUT_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_TOUT_INT_ST)) { - read_chars: - ETS_UART_INTR_DISABLE(); - - while (READ_PERI_REG(UART_STATUS(uart_no)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S)) { - uint8 RcvChar = READ_PERI_REG(UART_FIFO(uart_no)) & 0xff; - // For efficiency, when connected to dupterm we put incoming chars - // directly on stdin_ringbuf, rather than going via uart_ringbuf - if (uart_attached_to_dupterm) { - if (RcvChar == mp_interrupt_char) { - mp_keyboard_interrupt(); - } else { - ringbuf_put(&stdin_ringbuf, RcvChar); - } - } else { - ringbuf_put(&uart_ringbuf, RcvChar); - } - } - - // Clear pending FIFO interrupts - WRITE_PERI_REG(UART_INT_CLR(UART_REPL), UART_RXFIFO_TOUT_INT_CLR | UART_RXFIFO_FULL_INT_ST); - ETS_UART_INTR_ENABLE(); - - if (uart_attached_to_dupterm) { - mp_hal_signal_input(); - } - } -} - -// Waits at most timeout microseconds for at least 1 char to become ready for reading. -// Returns true if something available, false if not. -bool uart_rx_wait(uint32_t timeout_us) { - uint32_t start = system_get_time(); - for (;;) { - if (uart_ringbuf.iget != uart_ringbuf.iput) { - return true; // have at least 1 char ready for reading - } - if (system_get_time() - start >= timeout_us) { - return false; // timeout - } - ets_event_poll(); - } -} - -int uart_rx_any(uint8 uart) { - if (uart_ringbuf.iget != uart_ringbuf.iput) { - return true; // have at least 1 char ready for reading - } - return false; -} - -int uart_tx_any_room(uint8 uart) { - uint32_t fifo_cnt = READ_PERI_REG(UART_STATUS(uart)) & (UART_TXFIFO_CNT << UART_TXFIFO_CNT_S); - if ((fifo_cnt >> UART_TXFIFO_CNT_S & UART_TXFIFO_CNT) >= 126) { - return false; - } - return true; -} - -// Returns char from the input buffer, else -1 if buffer is empty. -int uart_rx_char(void) { - return ringbuf_get(&uart_ringbuf); -} - -int uart_rx_one_char(uint8 uart_no) { - if (READ_PERI_REG(UART_STATUS(uart_no)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S)) { - return READ_PERI_REG(UART_FIFO(uart_no)) & 0xff; - } - return -1; -} - -/****************************************************************************** - * FunctionName : uart_init - * Description : user interface for init uart - * Parameters : UartBautRate uart0_br - uart0 bautrate - * UartBautRate uart1_br - uart1 bautrate - * Returns : NONE -*******************************************************************************/ -void ICACHE_FLASH_ATTR uart_init(UartBautRate uart0_br, UartBautRate uart1_br) { - // rom use 74880 baut_rate, here reinitialize - UartDev.baut_rate = uart0_br; - uart_config(UART0); - UartDev.baut_rate = uart1_br; - uart_config(UART1); - ETS_UART_INTR_ENABLE(); - - // install handler for "os" messages - os_install_putc1((void *)uart_os_write_char); -} - -void ICACHE_FLASH_ATTR uart_reattach() { - uart_init(UART_BIT_RATE_74880, UART_BIT_RATE_74880); -} - -void ICACHE_FLASH_ATTR uart_setup(uint8 uart) { - ETS_UART_INTR_DISABLE(); - uart_config(uart); - ETS_UART_INTR_ENABLE(); -} - -// Task-based UART interface - -#include "py/obj.h" -#include "lib/utils/pyexec.h" - -#if MICROPY_REPL_EVENT_DRIVEN -void uart_task_handler(os_event_t *evt) { - if (pyexec_repl_active) { - // TODO: Just returning here isn't exactly right. - // What really should be done is something like - // enquing delayed event to itself, for another - // chance to feed data to REPL. Otherwise, there - // can be situation when buffer has bunch of data, - // and sits unprocessed, because we consumed all - // processing signals like this. - return; - } - - int c, ret = 0; - while ((c = ringbuf_get(&input_buf)) >= 0) { - if (c == mp_interrupt_char) { - mp_keyboard_interrupt(); - } - ret = pyexec_event_repl_process_char(c); - if (ret & PYEXEC_FORCED_EXIT) { - break; - } - } - - if (ret & PYEXEC_FORCED_EXIT) { - soft_reset(); - } -} - -void uart_task_init() { - system_os_task(uart_task_handler, UART_TASK_ID, uart_evt_queue, sizeof(uart_evt_queue) / sizeof(*uart_evt_queue)); -} -#endif diff --git a/ports/esp8266/espuart.h b/ports/esp8266/espuart.h deleted file mode 100644 index 684689a0e..000000000 --- a/ports/esp8266/espuart.h +++ /dev/null @@ -1,106 +0,0 @@ -#ifndef MICROPY_INCLUDED_ESP8266_UART_H -#define MICROPY_INCLUDED_ESP8266_UART_H - -#include - -#define UART0 (0) -#define UART1 (1) - -typedef enum { - UART_FIVE_BITS = 0x0, - UART_SIX_BITS = 0x1, - UART_SEVEN_BITS = 0x2, - UART_EIGHT_BITS = 0x3 -} UartBitsNum4Char; - -typedef enum { - UART_ONE_STOP_BIT = 0x1, - UART_ONE_HALF_STOP_BIT = 0x2, - UART_TWO_STOP_BIT = 0x3 -} UartStopBitsNum; - -typedef enum { - UART_NONE_BITS = 0, - UART_ODD_BITS = BIT0, - UART_EVEN_BITS = 0 -} UartParityMode; - -typedef enum { - UART_STICK_PARITY_DIS = 0, - UART_STICK_PARITY_EN = BIT1 -} UartExistParity; - -typedef enum { - UART_BIT_RATE_9600 = 9600, - UART_BIT_RATE_19200 = 19200, - UART_BIT_RATE_38400 = 38400, - UART_BIT_RATE_57600 = 57600, - UART_BIT_RATE_74880 = 74880, - UART_BIT_RATE_115200 = 115200, - UART_BIT_RATE_230400 = 230400, - UART_BIT_RATE_256000 = 256000, - UART_BIT_RATE_460800 = 460800, - UART_BIT_RATE_921600 = 921600 -} UartBautRate; - -typedef enum { - UART_NONE_CTRL, - UART_HARDWARE_CTRL, - UART_XON_XOFF_CTRL -} UartFlowCtrl; - -typedef enum { - UART_EMPTY, - UART_UNDER_WRITE, - UART_WRITE_OVER -} RcvMsgBuffState; - -typedef struct { - uint32 RcvBuffSize; - uint8 *pRcvMsgBuff; - uint8 *pWritePos; - uint8 *pReadPos; - uint8 TrigLvl; //JLU: may need to pad - RcvMsgBuffState BuffState; -} RcvMsgBuff; - -typedef struct { - uint32 TrxBuffSize; - uint8 *pTrxBuff; -} TrxMsgBuff; - -typedef enum { - UART_BAUD_RATE_DET, - UART_WAIT_SYNC_FRM, - UART_SRCH_MSG_HEAD, - UART_RCV_MSG_BODY, - UART_RCV_ESC_CHAR, -} RcvMsgState; - -typedef struct { - UartBautRate baut_rate; - UartBitsNum4Char data_bits; - UartExistParity exist_parity; - UartParityMode parity; // chip size in byte - UartStopBitsNum stop_bits; - UartFlowCtrl flow_ctrl; - RcvMsgBuff rcv_buff; - TrxMsgBuff trx_buff; - RcvMsgState rcv_state; - int received; - int buff_uart_no; //indicate which uart use tx/rx buffer -} UartDevice; - -void uart_init(UartBautRate uart0_br, UartBautRate uart1_br); -int uart0_rx(void); -bool uart_rx_wait(uint32_t timeout_us); -int uart_rx_char(void); -void uart_tx_one_char(uint8 uart, uint8 TxChar); -void uart_flush(uint8 uart); -void uart_os_config(int uart); -void uart_setup(uint8 uart); -// check status of rx/tx -int uart_rx_any(uint8 uart); -int uart_tx_any_room(uint8 uart); - -#endif // MICROPY_INCLUDED_ESP8266_UART_H diff --git a/ports/esp8266/etshal.h b/ports/esp8266/etshal.h index 7f6962d7a..8d6457311 100644 --- a/ports/esp8266/etshal.h +++ b/ports/esp8266/etshal.h @@ -6,12 +6,14 @@ // see http://esp8266-re.foogod.com/wiki/Random_Number_Generator #define WDEV_HWRNG ((volatile uint32_t*)0x3ff20e44) +void ets_delay_us(uint16_t us); void ets_intr_lock(void); void ets_intr_unlock(void); void ets_isr_mask(uint32_t mask); void ets_isr_unmask(uint32_t mask); void ets_isr_attach(int irq_no, void (*handler)(void *), void *arg); void ets_install_putc1(); +void uart_div_modify(uint8_t uart, uint32_t divisor); void ets_set_idle_cb(void (*handler)(void *), void *arg); void ets_timer_arm_new(os_timer_t *tim, uint32_t millis, bool repeat, bool is_milli_timer); @@ -30,6 +32,12 @@ void MD5Init(MD5_CTX *context); void MD5Update(MD5_CTX *context, const void *data, unsigned int len); void MD5Final(unsigned char digest[16], MD5_CTX *context); +// These prototypes are for recent SDKs with "malloc tracking" +void *pvPortMalloc(size_t sz, const char *fname, unsigned line); +void *pvPortZalloc(size_t sz, const char *fname, unsigned line); +void *pvPortRealloc(void *p, unsigned sz, const char *fname, unsigned line); +void vPortFree(void *p, const char *fname, unsigned 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); diff --git a/ports/esp8266/machine_uart.c b/ports/esp8266/machine_uart.c index 28fbfbaff..e8be5e538 100644 --- a/ports/esp8266/machine_uart.c +++ b/ports/esp8266/machine_uart.c @@ -29,7 +29,7 @@ #include #include "ets_sys.h" -#include "espuart.h" +#include "uart.h" #include "py/runtime.h" #include "py/stream.h" diff --git a/ports/esp8266/main.c b/ports/esp8266/main.c index da41b00c9..4882bf599 100644 --- a/ports/esp8266/main.c +++ b/ports/esp8266/main.c @@ -111,25 +111,6 @@ STATIC void mp_reset(void) { readline_init0(); dupterm_task_init(); pwmout_reset(); - - // Check if there are any dupterm objects registered and if not then - // activate UART(0), or else there will never be any chance to get a REPL - size_t idx; - for (idx = 0; idx < MICROPY_PY_OS_DUPTERM; ++idx) { - if (MP_STATE_VM(dupterm_objs[idx]) != MP_OBJ_NULL) { - break; - } - } - if (idx == MICROPY_PY_OS_DUPTERM) { - mp_obj_t args[2]; - args[0] = MP_OBJ_NEW_SMALL_INT(0); - args[1] = MP_OBJ_NEW_SMALL_INT(115200); - args[0] = pyb_uart_type.make_new(&pyb_uart_type, 2, 0, args); - args[1] = MP_OBJ_NEW_SMALL_INT(1); - extern mp_obj_t os_dupterm(size_t n_args, const mp_obj_t *args); - os_dupterm(2, args); - mp_hal_stdout_tx_str("Activated UART(0) for REPL\r\n"); - } } bool soft_reset(void) { diff --git a/ports/esp8266/modesp.c b/ports/esp8266/modesp.c index ec4e73503..76aa2cc21 100644 --- a/ports/esp8266/modesp.c +++ b/ports/esp8266/modesp.c @@ -30,7 +30,7 @@ #include "py/runtime.h" #include "py/mperrno.h" #include "py/mphal.h" -#include "espuart.h" +#include "uart.h" #include "user_interface.h" #include "mem.h" #include "modmachine.h" diff --git a/ports/esp8266/modnetwork.c b/ports/esp8266/modnetwork.c index e220808b1..c7f3397c4 100644 --- a/ports/esp8266/modnetwork.c +++ b/ports/esp8266/modnetwork.c @@ -426,9 +426,9 @@ STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs } case MP_QSTR_essid: if (self->if_id == STATION_IF) { - val = mp_obj_new_str((char*)cfg.sta.ssid, strlen((char*)cfg.sta.ssid), false); + val = mp_obj_new_str((char*)cfg.sta.ssid, strlen((char*)cfg.sta.ssid)); } else { - val = mp_obj_new_str((char*)cfg.ap.ssid, cfg.ap.ssid_len, false); + val = mp_obj_new_str((char*)cfg.ap.ssid, cfg.ap.ssid_len); } break; case MP_QSTR_hidden: diff --git a/ports/esp8266/modules/inisetup.py b/ports/esp8266/modules/inisetup.py index 7aa8bd435..46f089248 100644 --- a/ports/esp8266/modules/inisetup.py +++ b/ports/esp8266/modules/inisetup.py @@ -48,8 +48,6 @@ def setup(): # This file is executed on every boot (including wake-boot from deepsleep) #import esp #esp.osdebug(None) -import uos, machine -uos.dupterm(machine.UART(0, 115200), 1) import gc #import webrepl #webrepl.start() diff --git a/ports/esp8266/modules/webrepl_setup.py b/ports/esp8266/modules/webrepl_setup.py index 00b7c89e6..e87fac99e 100644 --- a/ports/esp8266/modules/webrepl_setup.py +++ b/ports/esp8266/modules/webrepl_setup.py @@ -34,6 +34,12 @@ def exists(fname): 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: @@ -44,6 +50,10 @@ def get_daemon_status(): 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()") diff --git a/ports/esp8266/modutime.c b/ports/esp8266/modutime.c index 64ecefb41..ab9cb7dc2 100644 --- a/ports/esp8266/modutime.c +++ b/ports/esp8266/modutime.c @@ -75,7 +75,7 @@ STATIC mp_obj_t time_localtime(size_t n_args, const mp_obj_t *args) { }; return mp_obj_new_tuple(8, tuple); } -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(utime_localtime_obj, 0, 1, time_localtime); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(time_localtime_obj, 0, 1, time_localtime); /// \function mktime() /// This is inverse function of localtime. It's argument is a full 8-tuple @@ -95,7 +95,7 @@ STATIC mp_obj_t time_mktime(mp_obj_t tuple) { mp_obj_get_int(elem[1]), mp_obj_get_int(elem[2]), mp_obj_get_int(elem[3]), mp_obj_get_int(elem[4]), mp_obj_get_int(elem[5]))); } -MP_DEFINE_CONST_FUN_OBJ_1(utime_mktime_obj, time_mktime); +MP_DEFINE_CONST_FUN_OBJ_1(time_mktime_obj, time_mktime); /// \function time() /// Returns the number of seconds, as an integer, since 1/1/2000. @@ -103,13 +103,13 @@ STATIC mp_obj_t time_time(void) { // get date and time return mp_obj_new_int(pyb_rtc_get_us_since_2000() / 1000 / 1000); } -MP_DEFINE_CONST_FUN_OBJ_0(utime_time_obj, time_time); +MP_DEFINE_CONST_FUN_OBJ_0(time_time_obj, time_time); STATIC const mp_rom_map_elem_t time_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_utime) }, - { MP_ROM_QSTR(MP_QSTR_localtime), MP_ROM_PTR(&utime_localtime_obj) }, - { MP_ROM_QSTR(MP_QSTR_mktime), MP_ROM_PTR(&utime_mktime_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) }, @@ -118,7 +118,7 @@ STATIC const mp_rom_map_elem_t time_module_globals_table[] = { { 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(&utime_time_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/ports/esp8266/mpconfigport.h b/ports/esp8266/mpconfigport.h index 84c18f996..eca3f525d 100644 --- a/ports/esp8266/mpconfigport.h +++ b/ports/esp8266/mpconfigport.h @@ -91,7 +91,7 @@ #define MICROPY_PY_FRAMEBUF (1) #define MICROPY_PY_MICROPYTHON_MEM_INFO (1) #define MICROPY_PY_OS_DUPTERM (2) -#define MICROPY_CPYTHON_COMPAT (0) +#define MICROPY_CPYTHON_COMPAT (1) #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) #define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT) #define MICROPY_FLOAT_HIGH_QUALITY_HASH (1) diff --git a/ports/esp8266/uart.c b/ports/esp8266/uart.c new file mode 100644 index 000000000..52707f981 --- /dev/null +++ b/ports/esp8266/uart.c @@ -0,0 +1,309 @@ +/****************************************************************************** + * Copyright 2013-2014 Espressif Systems (Wuxi) + * + * FileName: uart.c + * + * Description: Two UART mode configration and interrupt handler. + * Check your hardware connection while use this mode. + * + * Modification history: + * 2014/3/12, v1.0 create this file. +*******************************************************************************/ +#include "ets_sys.h" +#include "osapi.h" +#include "uart.h" +#include "osapi.h" +#include "uart_register.h" +#include "etshal.h" +#include "c_types.h" +#include "user_interface.h" +#include "esp_mphal.h" + +// seems that this is missing in the Espressif SDK +#define FUNC_U0RXD 0 + +#define UART_REPL UART0 + +// UartDev is defined and initialized in rom code. +extern UartDevice UartDev; + +// the uart to which OS messages go; -1 to disable +static int uart_os = UART_OS; + +#if MICROPY_REPL_EVENT_DRIVEN +static os_event_t uart_evt_queue[16]; +#endif + +// A small, static ring buffer for incoming chars +// This will only be populated if the UART is not attached to dupterm +static byte uart_ringbuf_array[16]; +static ringbuf_t uart_ringbuf = {uart_ringbuf_array, sizeof(uart_ringbuf_array), 0, 0}; + +static void uart0_rx_intr_handler(void *para); + +void soft_reset(void); +void mp_keyboard_interrupt(void); + +/****************************************************************************** + * FunctionName : uart_config + * Description : Internal used function + * UART0 used for data TX/RX, RX buffer size is 0x100, interrupt enabled + * UART1 just used for debug output + * Parameters : uart_no, use UART0 or UART1 defined ahead + * Returns : NONE +*******************************************************************************/ +static void ICACHE_FLASH_ATTR uart_config(uint8 uart_no) { + if (uart_no == UART1) { + PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_U1TXD_BK); + } else { + ETS_UART_INTR_ATTACH(uart0_rx_intr_handler, NULL); + PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD); + } + + uart_div_modify(uart_no, UART_CLK_FREQ / (UartDev.baut_rate)); + + WRITE_PERI_REG(UART_CONF0(uart_no), UartDev.exist_parity + | UartDev.parity + | (UartDev.stop_bits << UART_STOP_BIT_NUM_S) + | (UartDev.data_bits << UART_BIT_NUM_S)); + + // clear rx and tx fifo,not ready + SET_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST); + CLEAR_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST); + + if (uart_no == UART0) { + // set rx fifo trigger + WRITE_PERI_REG(UART_CONF1(uart_no), + ((0x10 & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S) | + ((0x10 & UART_RX_FLOW_THRHD) << UART_RX_FLOW_THRHD_S) | + UART_RX_FLOW_EN | + (0x02 & UART_RX_TOUT_THRHD) << UART_RX_TOUT_THRHD_S | + UART_RX_TOUT_EN); + SET_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_TOUT_INT_ENA | + UART_FRM_ERR_INT_ENA); + } else { + WRITE_PERI_REG(UART_CONF1(uart_no), + ((UartDev.rcv_buff.TrigLvl & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S)); + } + + // clear all interrupt + WRITE_PERI_REG(UART_INT_CLR(uart_no), 0xffff); + // enable rx_interrupt + SET_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_FULL_INT_ENA); +} + +/****************************************************************************** + * FunctionName : uart1_tx_one_char + * Description : Internal used function + * Use uart1 interface to transfer one char + * Parameters : uint8 TxChar - character to tx + * Returns : OK +*******************************************************************************/ +void uart_tx_one_char(uint8 uart, uint8 TxChar) { + while (true) { + uint32 fifo_cnt = READ_PERI_REG(UART_STATUS(uart)) & (UART_TXFIFO_CNT<> UART_TXFIFO_CNT_S & UART_TXFIFO_CNT) < 126) { + break; + } + } + WRITE_PERI_REG(UART_FIFO(uart), TxChar); +} + +void uart_flush(uint8 uart) { + while (true) { + uint32 fifo_cnt = READ_PERI_REG(UART_STATUS(uart)) & (UART_TXFIFO_CNT<> UART_TXFIFO_CNT_S & UART_TXFIFO_CNT) == 0) { + break; + } + } +} + +/****************************************************************************** + * FunctionName : uart1_write_char + * Description : Internal used function + * Do some special deal while tx char is '\r' or '\n' + * Parameters : char c - character to tx + * Returns : NONE +*******************************************************************************/ +static void ICACHE_FLASH_ATTR +uart_os_write_char(char c) { + if (uart_os == -1) { + return; + } + if (c == '\n') { + uart_tx_one_char(uart_os, '\r'); + uart_tx_one_char(uart_os, '\n'); + } else if (c == '\r') { + } else { + uart_tx_one_char(uart_os, c); + } +} + +void ICACHE_FLASH_ATTR +uart_os_config(int uart) { + uart_os = uart; +} + +/****************************************************************************** + * FunctionName : uart0_rx_intr_handler + * Description : Internal used function + * UART0 interrupt handler, add self handle code inside + * Parameters : void *para - point to ETS_UART_INTR_ATTACH's arg + * Returns : NONE +*******************************************************************************/ + +static void uart0_rx_intr_handler(void *para) { + /* uart0 and uart1 intr combine togther, when interrupt occur, see reg 0x3ff20020, bit2, bit0 represents + * uart1 and uart0 respectively + */ + + uint8 uart_no = UART_REPL; + + if (UART_FRM_ERR_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_FRM_ERR_INT_ST)) { + // frame error + WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_FRM_ERR_INT_CLR); + } + + if (UART_RXFIFO_FULL_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_FULL_INT_ST)) { + // fifo full + goto read_chars; + } else if (UART_RXFIFO_TOUT_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_TOUT_INT_ST)) { + read_chars: + ETS_UART_INTR_DISABLE(); + + while (READ_PERI_REG(UART_STATUS(uart_no)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S)) { + uint8 RcvChar = READ_PERI_REG(UART_FIFO(uart_no)) & 0xff; + // For efficiency, when connected to dupterm we put incoming chars + // directly on stdin_ringbuf, rather than going via uart_ringbuf + if (uart_attached_to_dupterm) { + if (RcvChar == mp_interrupt_char) { + mp_keyboard_interrupt(); + } else { + ringbuf_put(&stdin_ringbuf, RcvChar); + } + } else { + ringbuf_put(&uart_ringbuf, RcvChar); + } + } + + // Clear pending FIFO interrupts + WRITE_PERI_REG(UART_INT_CLR(UART_REPL), UART_RXFIFO_TOUT_INT_CLR | UART_RXFIFO_FULL_INT_ST); + ETS_UART_INTR_ENABLE(); + + if (uart_attached_to_dupterm) { + mp_hal_signal_input(); + } + } +} + +// Waits at most timeout microseconds for at least 1 char to become ready for reading. +// Returns true if something available, false if not. +bool uart_rx_wait(uint32_t timeout_us) { + uint32_t start = system_get_time(); + for (;;) { + if (uart_ringbuf.iget != uart_ringbuf.iput) { + return true; // have at least 1 char ready for reading + } + if (system_get_time() - start >= timeout_us) { + return false; // timeout + } + ets_event_poll(); + } +} + +int uart_rx_any(uint8 uart) { + if (uart_ringbuf.iget != uart_ringbuf.iput) { + return true; // have at least 1 char ready for reading + } + return false; +} + +int uart_tx_any_room(uint8 uart) { + uint32_t fifo_cnt = READ_PERI_REG(UART_STATUS(uart)) & (UART_TXFIFO_CNT << UART_TXFIFO_CNT_S); + if ((fifo_cnt >> UART_TXFIFO_CNT_S & UART_TXFIFO_CNT) >= 126) { + return false; + } + return true; +} + +// Returns char from the input buffer, else -1 if buffer is empty. +int uart_rx_char(void) { + return ringbuf_get(&uart_ringbuf); +} + +int uart_rx_one_char(uint8 uart_no) { + if (READ_PERI_REG(UART_STATUS(uart_no)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S)) { + return READ_PERI_REG(UART_FIFO(uart_no)) & 0xff; + } + return -1; +} + +/****************************************************************************** + * FunctionName : uart_init + * Description : user interface for init uart + * Parameters : UartBautRate uart0_br - uart0 bautrate + * UartBautRate uart1_br - uart1 bautrate + * Returns : NONE +*******************************************************************************/ +void ICACHE_FLASH_ATTR uart_init(UartBautRate uart0_br, UartBautRate uart1_br) { + // rom use 74880 baut_rate, here reinitialize + UartDev.baut_rate = uart0_br; + uart_config(UART0); + UartDev.baut_rate = uart1_br; + uart_config(UART1); + ETS_UART_INTR_ENABLE(); + + // install handler for "os" messages + os_install_putc1((void *)uart_os_write_char); +} + +void ICACHE_FLASH_ATTR uart_reattach() { + uart_init(UART_BIT_RATE_74880, UART_BIT_RATE_74880); +} + +void ICACHE_FLASH_ATTR uart_setup(uint8 uart) { + ETS_UART_INTR_DISABLE(); + uart_config(uart); + ETS_UART_INTR_ENABLE(); +} + +// Task-based UART interface + +#include "py/obj.h" +#include "lib/utils/pyexec.h" + +#if MICROPY_REPL_EVENT_DRIVEN +void uart_task_handler(os_event_t *evt) { + if (pyexec_repl_active) { + // TODO: Just returning here isn't exactly right. + // What really should be done is something like + // enquing delayed event to itself, for another + // chance to feed data to REPL. Otherwise, there + // can be situation when buffer has bunch of data, + // and sits unprocessed, because we consumed all + // processing signals like this. + return; + } + + int c, ret = 0; + while ((c = ringbuf_get(&input_buf)) >= 0) { + if (c == mp_interrupt_char) { + mp_keyboard_interrupt(); + } + ret = pyexec_event_repl_process_char(c); + if (ret & PYEXEC_FORCED_EXIT) { + break; + } + } + + if (ret & PYEXEC_FORCED_EXIT) { + soft_reset(); + } +} + +void uart_task_init() { + system_os_task(uart_task_handler, UART_TASK_ID, uart_evt_queue, sizeof(uart_evt_queue) / sizeof(*uart_evt_queue)); +} +#endif diff --git a/ports/esp8266/uart.h b/ports/esp8266/uart.h new file mode 100644 index 000000000..684689a0e --- /dev/null +++ b/ports/esp8266/uart.h @@ -0,0 +1,106 @@ +#ifndef MICROPY_INCLUDED_ESP8266_UART_H +#define MICROPY_INCLUDED_ESP8266_UART_H + +#include + +#define UART0 (0) +#define UART1 (1) + +typedef enum { + UART_FIVE_BITS = 0x0, + UART_SIX_BITS = 0x1, + UART_SEVEN_BITS = 0x2, + UART_EIGHT_BITS = 0x3 +} UartBitsNum4Char; + +typedef enum { + UART_ONE_STOP_BIT = 0x1, + UART_ONE_HALF_STOP_BIT = 0x2, + UART_TWO_STOP_BIT = 0x3 +} UartStopBitsNum; + +typedef enum { + UART_NONE_BITS = 0, + UART_ODD_BITS = BIT0, + UART_EVEN_BITS = 0 +} UartParityMode; + +typedef enum { + UART_STICK_PARITY_DIS = 0, + UART_STICK_PARITY_EN = BIT1 +} UartExistParity; + +typedef enum { + UART_BIT_RATE_9600 = 9600, + UART_BIT_RATE_19200 = 19200, + UART_BIT_RATE_38400 = 38400, + UART_BIT_RATE_57600 = 57600, + UART_BIT_RATE_74880 = 74880, + UART_BIT_RATE_115200 = 115200, + UART_BIT_RATE_230400 = 230400, + UART_BIT_RATE_256000 = 256000, + UART_BIT_RATE_460800 = 460800, + UART_BIT_RATE_921600 = 921600 +} UartBautRate; + +typedef enum { + UART_NONE_CTRL, + UART_HARDWARE_CTRL, + UART_XON_XOFF_CTRL +} UartFlowCtrl; + +typedef enum { + UART_EMPTY, + UART_UNDER_WRITE, + UART_WRITE_OVER +} RcvMsgBuffState; + +typedef struct { + uint32 RcvBuffSize; + uint8 *pRcvMsgBuff; + uint8 *pWritePos; + uint8 *pReadPos; + uint8 TrigLvl; //JLU: may need to pad + RcvMsgBuffState BuffState; +} RcvMsgBuff; + +typedef struct { + uint32 TrxBuffSize; + uint8 *pTrxBuff; +} TrxMsgBuff; + +typedef enum { + UART_BAUD_RATE_DET, + UART_WAIT_SYNC_FRM, + UART_SRCH_MSG_HEAD, + UART_RCV_MSG_BODY, + UART_RCV_ESC_CHAR, +} RcvMsgState; + +typedef struct { + UartBautRate baut_rate; + UartBitsNum4Char data_bits; + UartExistParity exist_parity; + UartParityMode parity; // chip size in byte + UartStopBitsNum stop_bits; + UartFlowCtrl flow_ctrl; + RcvMsgBuff rcv_buff; + TrxMsgBuff trx_buff; + RcvMsgState rcv_state; + int received; + int buff_uart_no; //indicate which uart use tx/rx buffer +} UartDevice; + +void uart_init(UartBautRate uart0_br, UartBautRate uart1_br); +int uart0_rx(void); +bool uart_rx_wait(uint32_t timeout_us); +int uart_rx_char(void); +void uart_tx_one_char(uint8 uart, uint8 TxChar); +void uart_flush(uint8 uart); +void uart_os_config(int uart); +void uart_setup(uint8 uart); +// check status of rx/tx +int uart_rx_any(uint8 uart); +int uart_tx_any_room(uint8 uart); + +#endif // MICROPY_INCLUDED_ESP8266_UART_H diff --git a/ports/nrf/mpconfigport.h b/ports/nrf/mpconfigport.h index 85396e5dd..8e279e98d 100644 --- a/ports/nrf/mpconfigport.h +++ b/ports/nrf/mpconfigport.h @@ -67,10 +67,6 @@ #define MICROPY_VFS (1) #define MICROPY_VFS_FAT (MICROPY_VFS) -// TODO these should be generic, not bound to fatfs -#define mp_type_fileio fatfs_type_fileio -#define mp_type_textio fatfs_type_textio - // use vfs's functions for import stat and builtin open #if MICROPY_VFS #define mp_import_stat mp_vfs_import_stat diff --git a/py/asmx86.h b/py/asmx86.h index eb6c03eac..0908b8c71 100644 --- a/py/asmx86.h +++ b/py/asmx86.h @@ -112,7 +112,7 @@ void asm_x86_mov_r32_to_local(asm_x86_t* as, int src_r32, int dest_local_num); void asm_x86_mov_local_addr_to_r32(asm_x86_t* as, int local_num, int dest_r32); void asm_x86_call_ind(asm_x86_t* as, void* ptr, mp_uint_t n_args, int temp_r32); -#ifdef GENERIC_ASM_API +#if defined(GENERIC_ASM_API) && GENERIC_ASM_API // The following macros provide a (mostly) arch-independent API to // generate native code, and are used by the native emitter. diff --git a/py/moduerrno.c b/py/moduerrno.c index 660fca07a..a3bb3396f 100644 --- a/py/moduerrno.c +++ b/py/moduerrno.c @@ -110,6 +110,7 @@ qstr mp_errno_to_str(mp_obj_t errno_val) { case EEXIST: return MP_QSTR_File_space_exists; case ENODEV: return MP_QSTR_Unsupported_space_operation; case EINVAL: return MP_QSTR_Invalid_space_argument; + case EROFS: return MP_QSTR_Read_hyphen_only_space_filesystem; } } diff --git a/shared-module/os/__init__.c b/shared-module/os/__init__.c index 67d489f37..a38f3781f 100644 --- a/shared-module/os/__init__.c +++ b/shared-module/os/__init__.c @@ -112,9 +112,8 @@ mp_obj_t common_hal_os_listdir(const char* path) { mp_obj_t dir_list = mp_obj_new_list(0, NULL); mp_obj_t next; while ((next = mp_iternext(iter_obj)) != MP_OBJ_STOP_ITERATION) { - mp_obj_t *items; - mp_obj_get_array_fixed_n(next, 3, &items); - mp_obj_list_append(dir_list, items[0]); + // next[0] is the filename. + mp_obj_list_append(dir_list, mp_obj_subscr(next, MP_OBJ_NEW_SMALL_INT(0), MP_OBJ_SENTINEL)); } return dir_list; } -- cgit v1.2.3 From a99f9427420d0b519881dacd1a28007d6c1d71d0 Mon Sep 17 00:00:00 2001 From: Leszek Jakubowski Date: Sat, 28 Jul 2018 17:07:22 +0200 Subject: '/' and '\' are also acceptable ends of the path now --- lib/oofatfs/ff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/oofatfs/ff.c b/lib/oofatfs/ff.c index b0984756b..4e8680545 100644 --- a/lib/oofatfs/ff.c +++ b/lib/oofatfs/ff.c @@ -2579,8 +2579,8 @@ FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create if (w < 0x80 && chk_chr("\"*:<>\?|\x7F", w)) return FR_INVALID_NAME; /* Reject illegal characters for LFN */ lfn[di++] = w; /* Store the Unicode character */ } + cf = ((w < ' ') || ((w == '/' || w == '\\') && p[si+1] < ' ')) ? NS_LAST : 0; /* Set last segment flag if end of the path */ *path = &p[si]; /* Return pointer to the next segment */ - cf = (w < ' ') ? NS_LAST : 0; /* Set last segment flag if end of the path */ #if _FS_RPATH != 0 if ((di == 1 && lfn[di - 1] == '.') || (di == 2 && lfn[di - 1] == '.' && lfn[di - 2] == '.')) { /* Is this segment a dot name? */ -- cgit v1.2.3 From f48b70050e3e4122eaae3eee47d35fc30bda2a4c Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sat, 28 Jul 2018 13:29:47 -0400 Subject: merge finished --- extmod/moduhashlib.c | 16 +++++------ extmod/vfs_fat.h | 9 ------- extmod/vfs_fat_diskio.c | 6 +++-- lib/mp-readline/readline.h | 2 ++ ports/atmel-samd/mpconfigport.h | 3 +++ ports/esp8266/common-hal/neopixel_write/__init__.c | 2 +- ports/esp8266/esp_mphal.c | 23 ++++++++++------ ports/esp8266/esp_mphal.h | 3 --- ports/esp8266/uart.c | 31 +++++++--------------- ports/nrf/modules/ubluepy/ubluepy_scan_entry.c | 2 +- ports/nrf/modules/ubluepy/ubluepy_scanner.c | 2 +- ports/unix/Makefile | 3 +++ ports/unix/coverage.c | 2 +- py/binary.c | 4 +-- py/frozenmod.c | 8 +++++- py/objnamedtuple.h | 6 ++--- shared-bindings/bleio/Adapter.c | 2 +- tests/import/mpy_invalid.py.exp | 6 ++--- tests/run-tests | 4 +-- 19 files changed, 66 insertions(+), 68 deletions(-) (limited to 'lib') diff --git a/extmod/moduhashlib.c b/extmod/moduhashlib.c index 6389455c0..5e14fc8d4 100644 --- a/extmod/moduhashlib.c +++ b/extmod/moduhashlib.c @@ -29,14 +29,6 @@ #include "py/runtime.h" -static void check_not_unicode(const mp_obj_t arg) { -#if MICROPY_CPYTHON_COMPAT - if (MP_OBJ_IS_STR(arg)) { - mp_raise_TypeError("a bytes-like object is required"); - } -#endif -} - #if MICROPY_PY_UHASHLIB #if MICROPY_PY_UHASHLIB_SHA256 @@ -102,6 +94,14 @@ STATIC mp_obj_t uhashlib_sha256_digest(mp_obj_t self_in) { #else +static void check_not_unicode(const mp_obj_t arg) { +#if MICROPY_CPYTHON_COMPAT + if (MP_OBJ_IS_STR(arg)) { + mp_raise_TypeError("a bytes-like object is required"); + } +#endif +} + STATIC mp_obj_t uhashlib_sha256_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, 0, 1, false); mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(CRYAL_SHA256_CTX)); diff --git a/extmod/vfs_fat.h b/extmod/vfs_fat.h index ded8bc885..dd5e5ffcb 100644 --- a/extmod/vfs_fat.h +++ b/extmod/vfs_fat.h @@ -60,15 +60,6 @@ typedef struct _pyb_file_obj_t { FIL fp; } pyb_file_obj_t; - -// These should be general types (mpy TOOD says so). In micropython, these are defined in -// mpconfigport.h. -////////////#define mp_type_fileio mp_type_vfs_fat_fileio -////////////#define mp_type_textio mp_type_vfs_fat_textio - -////////////extern const mp_obj_type_t mp_type_fileio; -////////////extern const mp_obj_type_t mp_type_textio; - extern const byte fresult_to_errno_table[20]; extern const mp_obj_type_t mp_fat_vfs_type; extern const mp_obj_type_t mp_type_vfs_fat_fileio; diff --git a/extmod/vfs_fat_diskio.c b/extmod/vfs_fat_diskio.c index 3b5c7d888..0e442d8fa 100644 --- a/extmod/vfs_fat_diskio.c +++ b/extmod/vfs_fat_diskio.c @@ -75,8 +75,9 @@ DRESULT disk_read ( return RES_ERROR; } } else { + mp_obj_array_t ar = {{&mp_type_bytearray}, BYTEARRAY_TYPECODE, 0, count * SECSIZE(&vfs->fatfs), buff}; vfs->readblocks[2] = MP_OBJ_NEW_SMALL_INT(sector); - vfs->readblocks[3] = mp_obj_new_bytearray_by_ref(count * SECSIZE(&vfs->fatfs), buff); + vfs->readblocks[3] = MP_OBJ_FROM_PTR(&ar); nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { mp_obj_t ret = mp_call_method_n_kw(2, 0, vfs->readblocks); @@ -120,8 +121,9 @@ DRESULT disk_write ( return RES_ERROR; } } else { + mp_obj_array_t ar = {{&mp_type_bytearray}, BYTEARRAY_TYPECODE, 0, count * SECSIZE(&vfs->fatfs), (void*)buff}; vfs->writeblocks[2] = MP_OBJ_NEW_SMALL_INT(sector); - vfs->writeblocks[3] = mp_obj_new_bytearray_by_ref(count * SECSIZE(&vfs->fatfs), (void*)buff); + vfs->writeblocks[3] = MP_OBJ_FROM_PTR(&ar); nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { mp_obj_t ret = mp_call_method_n_kw(2, 0, vfs->writeblocks); diff --git a/lib/mp-readline/readline.h b/lib/mp-readline/readline.h index 00aa9622a..17d4ec60e 100644 --- a/lib/mp-readline/readline.h +++ b/lib/mp-readline/readline.h @@ -26,6 +26,8 @@ #ifndef MICROPY_INCLUDED_LIB_MP_READLINE_READLINE_H #define MICROPY_INCLUDED_LIB_MP_READLINE_READLINE_H +#include "py/misc.h" + #define CHAR_CTRL_A (1) #define CHAR_CTRL_B (2) #define CHAR_CTRL_C (3) diff --git a/ports/atmel-samd/mpconfigport.h b/ports/atmel-samd/mpconfigport.h index 6324e7a93..49f71b221 100644 --- a/ports/atmel-samd/mpconfigport.h +++ b/ports/atmel-samd/mpconfigport.h @@ -123,6 +123,9 @@ typedef long mp_off_t; #define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len) +#define mp_type_fileio mp_type_vfs_fat_fileio +#define mp_type_textio mp_type_vfs_fat_textio + #define mp_import_stat mp_vfs_import_stat #define mp_builtin_open_obj mp_vfs_open_obj diff --git a/ports/esp8266/common-hal/neopixel_write/__init__.c b/ports/esp8266/common-hal/neopixel_write/__init__.c index 84a743d11..25fb0dcea 100644 --- a/ports/esp8266/common-hal/neopixel_write/__init__.c +++ b/ports/esp8266/common-hal/neopixel_write/__init__.c @@ -29,5 +29,5 @@ #include "espneopixel.h" void common_hal_neopixel_write(const digitalio_digitalinout_obj_t* digitalinout, uint8_t *pixels, uint32_t numBytes) { - esp_neopixel_write(digitalinout->pin->gpio_number, pixels, numBytes); + esp_neopixel_write(digitalinout->pin->gpio_number, pixels, numBytes, true /*800 kHz*/); } diff --git a/ports/esp8266/esp_mphal.c b/ports/esp8266/esp_mphal.c index be284c8f3..fe669265e 100644 --- a/ports/esp8266/esp_mphal.c +++ b/ports/esp8266/esp_mphal.c @@ -35,18 +35,15 @@ #include "extmod/misc.h" #include "lib/utils/pyexec.h" -STATIC byte stdin_ringbuf_array[256]; -ringbuf_t stdin_ringbuf = {stdin_ringbuf_array, sizeof(stdin_ringbuf_array), 0, 0}; +STATIC byte input_buf_array[256]; +ringbuf_t stdin_ringbuf = {input_buf_array, sizeof(input_buf_array)}; void mp_hal_debug_tx_strn_cooked(void *env, const char *str, uint32_t len); const mp_print_t mp_debug_print = {NULL, mp_hal_debug_tx_strn_cooked}; -int uart_attached_to_dupterm; - void mp_hal_init(void) { //ets_wdt_disable(); // it's a pain while developing mp_hal_rtc_init(); uart_init(UART_BIT_RATE_115200, UART_BIT_RATE_115200); - uart_attached_to_dupterm = 0; } void mp_hal_delay_us(uint32_t us) { @@ -87,11 +84,19 @@ void mp_hal_debug_str(const char *str) { #endif void mp_hal_stdout_tx_str(const char *str) { - mp_uos_dupterm_tx_strn(str, strlen(str)); + const char *last = str; + while (*str) { + uart_tx_one_char(UART0, *str++); + } + mp_uos_dupterm_tx_strn(last, str - last); } void mp_hal_stdout_tx_strn(const char *str, uint32_t len) { - mp_uos_dupterm_tx_strn(str, len); + const char *last = str; + while (len--) { + uart_tx_one_char(UART0, *str++); + } + mp_uos_dupterm_tx_strn(last, str - last); } void mp_hal_stdout_tx_strn_cooked(const char *str, uint32_t len) { @@ -101,11 +106,13 @@ void mp_hal_stdout_tx_strn_cooked(const char *str, uint32_t len) { if (str > last) { mp_uos_dupterm_tx_strn(last, str - last); } + uart_tx_one_char(UART0, '\r'); + uart_tx_one_char(UART0, '\n'); mp_uos_dupterm_tx_strn("\r\n", 2); ++str; last = str; } else { - ++str; + uart_tx_one_char(UART0, *str++); } } if (str > last) { diff --git a/ports/esp8266/esp_mphal.h b/ports/esp8266/esp_mphal.h index 56d9fa35f..5ecd392a6 100644 --- a/ports/esp8266/esp_mphal.h +++ b/ports/esp8266/esp_mphal.h @@ -40,9 +40,6 @@ void mp_hal_signal_input(void); // Call this when data is available in dupterm object void mp_hal_signal_dupterm_input(void); -// This variable counts how many times the UART is attached to dupterm -extern int uart_attached_to_dupterm; - void mp_hal_init(void); void mp_hal_rtc_init(void); diff --git a/ports/esp8266/uart.c b/ports/esp8266/uart.c index 52707f981..4a8405337 100644 --- a/ports/esp8266/uart.c +++ b/ports/esp8266/uart.c @@ -34,11 +34,6 @@ static int uart_os = UART_OS; static os_event_t uart_evt_queue[16]; #endif -// A small, static ring buffer for incoming chars -// This will only be populated if the UART is not attached to dupterm -static byte uart_ringbuf_array[16]; -static ringbuf_t uart_ringbuf = {uart_ringbuf_array, sizeof(uart_ringbuf_array), 0, 0}; - static void uart0_rx_intr_handler(void *para); void soft_reset(void); @@ -175,26 +170,18 @@ static void uart0_rx_intr_handler(void *para) { while (READ_PERI_REG(UART_STATUS(uart_no)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S)) { uint8 RcvChar = READ_PERI_REG(UART_FIFO(uart_no)) & 0xff; - // For efficiency, when connected to dupterm we put incoming chars - // directly on stdin_ringbuf, rather than going via uart_ringbuf - if (uart_attached_to_dupterm) { - if (RcvChar == mp_interrupt_char) { - mp_keyboard_interrupt(); - } else { - ringbuf_put(&stdin_ringbuf, RcvChar); - } + if (RcvChar == mp_interrupt_char) { + mp_keyboard_interrupt(); } else { - ringbuf_put(&uart_ringbuf, RcvChar); + ringbuf_put(&stdin_ringbuf, RcvChar); } } + mp_hal_signal_input(); + // Clear pending FIFO interrupts WRITE_PERI_REG(UART_INT_CLR(UART_REPL), UART_RXFIFO_TOUT_INT_CLR | UART_RXFIFO_FULL_INT_ST); ETS_UART_INTR_ENABLE(); - - if (uart_attached_to_dupterm) { - mp_hal_signal_input(); - } } } @@ -203,7 +190,7 @@ static void uart0_rx_intr_handler(void *para) { bool uart_rx_wait(uint32_t timeout_us) { uint32_t start = system_get_time(); for (;;) { - if (uart_ringbuf.iget != uart_ringbuf.iput) { + if (stdin_ringbuf.iget != stdin_ringbuf.iput) { return true; // have at least 1 char ready for reading } if (system_get_time() - start >= timeout_us) { @@ -214,7 +201,7 @@ bool uart_rx_wait(uint32_t timeout_us) { } int uart_rx_any(uint8 uart) { - if (uart_ringbuf.iget != uart_ringbuf.iput) { + if (stdin_ringbuf.iget != stdin_ringbuf.iput) { return true; // have at least 1 char ready for reading } return false; @@ -230,7 +217,7 @@ int uart_tx_any_room(uint8 uart) { // Returns char from the input buffer, else -1 if buffer is empty. int uart_rx_char(void) { - return ringbuf_get(&uart_ringbuf); + return ringbuf_get(&stdin_ringbuf); } int uart_rx_one_char(uint8 uart_no) { @@ -288,7 +275,7 @@ void uart_task_handler(os_event_t *evt) { } int c, ret = 0; - while ((c = ringbuf_get(&input_buf)) >= 0) { + while ((c = ringbuf_get(&stdin_ringbuf)) >= 0) { if (c == mp_interrupt_char) { mp_keyboard_interrupt(); } diff --git a/ports/nrf/modules/ubluepy/ubluepy_scan_entry.c b/ports/nrf/modules/ubluepy/ubluepy_scan_entry.c index 8a936d592..773070b08 100644 --- a/ports/nrf/modules/ubluepy/ubluepy_scan_entry.c +++ b/ports/nrf/modules/ubluepy/ubluepy_scan_entry.c @@ -109,7 +109,7 @@ STATIC mp_obj_t scan_entry_get_scan_data(mp_obj_t self_in) { vstr_t vstr; vstr_init(&vstr, len); vstr_printf(&vstr, "%s", text); - description = mp_obj_new_str(vstr.buf, vstr.len, false); + description = mp_obj_new_str(vstr.buf, vstr.len); vstr_clear(&vstr); } } diff --git a/ports/nrf/modules/ubluepy/ubluepy_scanner.c b/ports/nrf/modules/ubluepy/ubluepy_scanner.c index c92b7fd87..1cde3d551 100644 --- a/ports/nrf/modules/ubluepy/ubluepy_scanner.c +++ b/ports/nrf/modules/ubluepy/ubluepy_scanner.c @@ -49,7 +49,7 @@ STATIC void adv_event_handler(mp_obj_t self_in, uint16_t event_id, ble_drv_adv_d data->p_peer_addr[5], data->p_peer_addr[4], data->p_peer_addr[3], data->p_peer_addr[2], data->p_peer_addr[1], data->p_peer_addr[0]); - item->addr = mp_obj_new_str(vstr.buf, vstr.len, false); + item->addr = mp_obj_new_str(vstr.buf, vstr.len); vstr_clear(&vstr); diff --git a/ports/unix/Makefile b/ports/unix/Makefile index 1136c42b6..104ad3e5d 100644 --- a/ports/unix/Makefile +++ b/ports/unix/Makefile @@ -261,6 +261,9 @@ coverage_test: coverage gcov -o build-coverage/py $(TOP)/py/*.c gcov -o build-coverage/extmod $(TOP)/extmod/*.c +coverage_clean: + $(MAKE) V=2 BUILD=build-coverage PROG=micropython_coverage clean + # Value of configure's --host= option (required for cross-compilation). # Deduce it from CROSS_COMPILE by default, but can be overridden. ifneq ($(CROSS_COMPILE),) diff --git a/ports/unix/coverage.c b/ports/unix/coverage.c index 7820f6d73..841924c58 100644 --- a/ports/unix/coverage.c +++ b/ports/unix/coverage.c @@ -173,7 +173,7 @@ STATIC mp_obj_t extra_coverage(void) { gc_unlock(); // using gc_realloc to resize to 0, which means free the memory - void *p = gc_alloc(4, false); + void *p = gc_alloc(4, false, false); mp_printf(&mp_plat_print, "%p\n", gc_realloc(p, 0, false)); // calling gc_nbytes with a non-heap pointer diff --git a/py/binary.c b/py/binary.c index bb334ed3d..4f02525d7 100644 --- a/py/binary.c +++ b/py/binary.c @@ -148,7 +148,7 @@ mp_obj_t mp_binary_get_val_array(char typecode, void *p, mp_uint_t index) { #endif #if MICROPY_PY_BUILTINS_FLOAT case 'f': - return mp_obj_new_float((mp_float_t)((float*)p)[index]); + return mp_obj_new_float(((float*)p)[index]); case 'd': return mp_obj_new_float(((double*)p)[index]); #endif @@ -213,7 +213,7 @@ mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr) { #if MICROPY_NONSTANDARD_TYPECODES } else if (val_type == 'S') { const char *s_val = (const char*)(uintptr_t)(mp_uint_t)val; - return mp_obj_new_str(s_val, strlen(s_val), false); + return mp_obj_new_str(s_val, strlen(s_val)); #endif #if MICROPY_PY_BUILTINS_FLOAT } else if (val_type == 'f') { diff --git a/py/frozenmod.c b/py/frozenmod.c index 5464d0af9..a9143b582 100644 --- a/py/frozenmod.c +++ b/py/frozenmod.c @@ -43,8 +43,14 @@ extern const char mp_frozen_str_names[]; extern const uint32_t mp_frozen_str_sizes[]; extern const char mp_frozen_str_content[]; -// On input, *len contains size of name, on output - size of content +// str_len is length of str. *len is set on on output to size of content const char *mp_find_frozen_str(const char *str, size_t str_len, size_t *len) { + // If the frozen module pseudo dir (e.g., ".frozen/") is a prefix of str, remove it. + if (strncmp(str, MP_FROZEN_FAKE_DIR_SLASH, MP_FROZEN_FAKE_DIR_SLASH_LENGTH) == 0) { + str = str + MP_FROZEN_FAKE_DIR_SLASH_LENGTH; + str_len = str_len - MP_FROZEN_FAKE_DIR_SLASH_LENGTH; + } + const char *name = mp_frozen_str_names; size_t offset = 0; diff --git a/py/objnamedtuple.h b/py/objnamedtuple.h index a36404b8d..deac7107b 100644 --- a/py/objnamedtuple.h +++ b/py/objnamedtuple.h @@ -39,7 +39,7 @@ typedef struct _mp_obj_namedtuple_type_t { mp_obj_type_t base; - mp_uint_t n_fields; + size_t n_fields; qstr fields[]; } mp_obj_namedtuple_type_t; @@ -48,9 +48,9 @@ typedef struct _mp_obj_namedtuple_t { } mp_obj_namedtuple_t; void namedtuple_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind); - +size_t mp_obj_namedtuple_find_field(const mp_obj_namedtuple_type_t *type, qstr name); void namedtuple_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest); - +mp_obj_namedtuple_type_t *mp_obj_new_namedtuple_base(size_t n_fields, mp_obj_t *fields); mp_obj_t namedtuple_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args); #endif // MICROPY_PY_COLLECTIONS diff --git a/shared-bindings/bleio/Adapter.c b/shared-bindings/bleio/Adapter.c index 81efea54e..bfe87071d 100644 --- a/shared-bindings/bleio/Adapter.c +++ b/shared-bindings/bleio/Adapter.c @@ -86,7 +86,7 @@ STATIC mp_obj_t bleio_adapter_get_address(mp_obj_t self) { common_hal_bleio_adapter_get_address(&vstr); - const mp_obj_t mac_str = mp_obj_new_str(vstr.buf, vstr.len, false); + const mp_obj_t mac_str = mp_obj_new_str(vstr.buf, vstr.len); vstr_clear(&vstr); diff --git a/tests/import/mpy_invalid.py.exp b/tests/import/mpy_invalid.py.exp index 1727ea1ce..e4f2b13e9 100644 --- a/tests/import/mpy_invalid.py.exp +++ b/tests/import/mpy_invalid.py.exp @@ -1,3 +1,3 @@ -mod0 ValueError incompatible .mpy file -mod1 ValueError incompatible .mpy file -mod2 ValueError incompatible .mpy file +mod0 ValueError Incompatible .mpy file. Please update all .mpy files. See http://adafru.it/mpy-update for more info. +mod1 ValueError Incompatible .mpy file. Please update all .mpy files. See http://adafru.it/mpy-update for more info. +mod2 ValueError Incompatible .mpy file. Please update all .mpy files. See http://adafru.it/mpy-update for more info. diff --git a/tests/run-tests b/tests/run-tests index 3064f6845..94e1591e8 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -396,7 +396,7 @@ def run_tests(pyb, tests, args, base_path=".", num_threads=1): if pat.search(test_file): verdict = action if verdict == "exclude": - continue + return test_basename = os.path.basename(test_file) test_name = os.path.splitext(test_basename)[0] @@ -419,7 +419,7 @@ def run_tests(pyb, tests, args, base_path=".", num_threads=1): if args.list_tests: if not skip_it: print(test_file) - continue + return if skip_it: print("skip ", test_file) -- cgit v1.2.3