From 5c7ac55232670aaccfc2d05d75f5d7a6772a61ef Mon Sep 17 00:00:00 2001 From: Glenn Moloney Date: Sat, 26 Oct 2024 15:19:54 +1100 Subject: [PATCH 01/22] tools/mpremote: Fix UnboundLocalError in Transport.fs_writefile(). The variable `written` was being used before it was defined in the `fs_writefile()` method of the Transport class. This was causing an `UnboundLocalError` to be raised when the `progress_callback` was not provided. Fixes issue #16084. Signed-off-by: Glenn Moloney --- tools/mpremote/mpremote/transport.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/mpremote/mpremote/transport.py b/tools/mpremote/mpremote/transport.py index 0b22a61580a03..d845796953a29 100644 --- a/tools/mpremote/mpremote/transport.py +++ b/tools/mpremote/mpremote/transport.py @@ -151,9 +151,9 @@ def fs_writefile(self, dest, data, chunk_size=256, progress_callback=None): while data: chunk = data[:chunk_size] self.exec("w(" + repr(chunk) + ")") - written += len(chunk) data = data[len(chunk) :] if progress_callback: + written += len(chunk) progress_callback(written, src_size) self.exec("f.close()") except TransportExecError as e: From 785c92df7642577b1b1980aaaf92f86c0183895b Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Sun, 27 Oct 2024 14:51:37 +1100 Subject: [PATCH 02/22] esp32/machine_pwm: Use IDF functions to calculate resolution correctly. This commit fixes PWM configuration across C3, C6, S2 and S3 chips, which was broken by 6d799378bad4474e77ddb2fa2187ecd6e290e0ba. Without this fix the PWM frequency is limited to a maximum of 2446Hz (on S2 at least). Signed-off-by: Andrew Leech --- ports/esp32/machine_pwm.c | 50 +++++++++++++-------------------------- 1 file changed, 16 insertions(+), 34 deletions(-) diff --git a/ports/esp32/machine_pwm.c b/ports/esp32/machine_pwm.c index 71402e1c49e44..61efdfa18548b 100644 --- a/ports/esp32/machine_pwm.c +++ b/ports/esp32/machine_pwm.c @@ -34,6 +34,7 @@ #include "py/mphal.h" #include "driver/ledc.h" #include "esp_err.h" +#include "esp_clk_tree.h" #include "soc/gpio_sig_map.h" #define PWM_DBG(...) @@ -209,51 +210,32 @@ static void configure_channel(machine_pwm_obj_t *self) { static void set_freq(machine_pwm_obj_t *self, unsigned int freq, ledc_timer_config_t *timer) { if (freq != timer->freq_hz) { - // Find the highest bit resolution for the requested frequency - unsigned int i = APB_CLK_FREQ; // 80 MHz - #if SOC_LEDC_SUPPORT_REF_TICK - if (freq < EMPIRIC_FREQ) { - i = REF_CLK_FREQ; // 1 MHz - } - #endif - - int divider = (i + freq / 2) / freq; // rounded - if (divider == 0) { - divider = 1; - } - float f = (float)i / divider; // actual frequency - if (f <= 1.0) { - f = 1.0; - } - i = (unsigned int)roundf((float)i / f); - - unsigned int res = 0; - for (; i > 1; i >>= 1) { - ++res; - } - if (res == 0) { - res = 1; - } else if (res > HIGHEST_PWM_RES) { - // Limit resolution to HIGHEST_PWM_RES to match units of our duty - res = HIGHEST_PWM_RES; - } - - // Configure the new resolution and frequency - timer->duty_resolution = res; + // Configure the new frequency and resolution timer->freq_hz = freq; - #if SOC_LEDC_SUPPORT_XTAL_CLOCK + + #if SOC_LEDC_SUPPORT_PLL_DIV_CLOCK + timer->clk_cfg = LEDC_USE_PLL_DIV_CLK; + #elif SOC_LEDC_SUPPORT_APB_CLOCK + timer->clk_cfg = LEDC_USE_APB_CLK; + #elif SOC_LEDC_SUPPORT_XTAL_CLOCK timer->clk_cfg = LEDC_USE_XTAL_CLK; #else - timer->clk_cfg = LEDC_USE_APB_CLK; + #error No supported PWM / LEDC clocks. #endif #if SOC_LEDC_SUPPORT_REF_TICK if (freq < EMPIRIC_FREQ) { timer->clk_cfg = LEDC_USE_REF_TICK; } #endif + uint32_t src_clk_freq = 0; + esp_err_t err = esp_clk_tree_src_get_freq_hz(timer->clk_cfg, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &src_clk_freq); + if (err != ESP_OK) { + mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("unable to query source clock frequency %d"), (int)timer->clk_cfg); + } + timer->duty_resolution = ledc_find_suitable_duty_resolution(src_clk_freq, timer->freq_hz); // Set frequency - esp_err_t err = ledc_timer_config(timer); + err = ledc_timer_config(timer); if (err != ESP_OK) { if (err == ESP_FAIL) { mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("unreachable frequency %d"), freq); From c0afff8f22ccb84ab46b01ebcd5e1e49803a71cb Mon Sep 17 00:00:00 2001 From: Alessandro Gatti Date: Thu, 12 Sep 2024 13:08:32 +0200 Subject: [PATCH 03/22] pic16bit: Make it build with recent XC16 versions. The PIC16 port didn't catch up with the other ports, so it required a bit of work to make it build with the latest version of XC16. Signed-off-by: Alessandro Gatti --- ports/pic16bit/Makefile | 4 ++-- ports/pic16bit/mpconfigport.h | 4 ---- py/misc.h | 13 +++++++++++++ 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/ports/pic16bit/Makefile b/ports/pic16bit/Makefile index 6d061514f9583..dda48fa3ce5f1 100644 --- a/ports/pic16bit/Makefile +++ b/ports/pic16bit/Makefile @@ -7,7 +7,7 @@ QSTR_DEFS = qstrdefsport.h include $(TOP)/py/py.mk include $(TOP)/extmod/extmod.mk -XCVERSION ?= 1.35 +XCVERSION ?= 2.10 XC16 ?= /opt/microchip/xc16/v$(XCVERSION) CROSS_COMPILE ?= $(XC16)/bin/xc16- @@ -31,7 +31,7 @@ CFLAGS += -O1 -DNDEBUG endif LDFLAGS += --heap=0 -nostdlib -T $(XC16)/support/$(PARTFAMILY)/gld/p$(PART).gld -Map=$@.map --cref -p$(PART) -LIBS += -L$(XC16)/lib -L$(XC16)/lib/$(PARTFAMILY) -lc -lm -lpic30 +LIBS += -L$(XC16)/lib -L$(XC16)/lib/$(PARTFAMILY) -lc99-elf -lm-elf -lc99-pic30-elf SRC_C = \ main.c \ diff --git a/ports/pic16bit/mpconfigport.h b/ports/pic16bit/mpconfigport.h index a2d607fb29325..d80f7edb9e546 100644 --- a/ports/pic16bit/mpconfigport.h +++ b/ports/pic16bit/mpconfigport.h @@ -93,7 +93,3 @@ typedef int mp_off_t; #define MICROPY_MPHALPORT_H "pic16bit_mphal.h" #define MICROPY_HW_BOARD_NAME "dsPICSK" #define MICROPY_HW_MCU_NAME "dsPIC33" - -// XC16 toolchain doesn't seem to define these -typedef int intptr_t; -typedef unsigned int uintptr_t; diff --git a/py/misc.h b/py/misc.h index 96b13c151a6b9..8ac80bb7b3e34 100644 --- a/py/misc.h +++ b/py/misc.h @@ -380,6 +380,18 @@ static inline bool mp_check(bool value) { // mp_int_t can be larger than long, i.e. Windows 64-bit, nan-box variants static inline uint32_t mp_clz_mpi(mp_int_t x) { + #ifdef __XC16__ + mp_uint_t mask = MP_OBJ_WORD_MSBIT_HIGH; + mp_uint_t zeroes = 0; + while (mask != 0) { + if (mask & (mp_uint_t)x) { + break; + } + zeroes++; + mask >>= 1; + } + return zeroes; + #else MP_STATIC_ASSERT(sizeof(mp_int_t) == sizeof(long long) || sizeof(mp_int_t) == sizeof(long)); @@ -389,6 +401,7 @@ static inline uint32_t mp_clz_mpi(mp_int_t x) { } else { return mp_clzll((unsigned long long)x); } + #endif } #endif // MICROPY_INCLUDED_PY_MISC_H From a7d3bc23085fdc4dfe9bf644daf7fa6f2d5559df Mon Sep 17 00:00:00 2001 From: Jan Sturm Date: Tue, 29 Oct 2024 19:26:19 +0100 Subject: [PATCH 04/22] py/objdeque: Fix buffer overflow in deque_subscr. In `deque_subscr()`, if `index_val` equals `self->alloc`, the index correction `index_val -= self->alloc` does not execute, leading to an out-of-bounds access in `self->items[index_val]`. The fix in this commit ensures that the index correction is applied whenever `index_val >= self->alloc`, preventing access beyond the allocated buffer size. Signed-off-by: Jan Sturm --- py/objdeque.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/objdeque.c b/py/objdeque.c index 2ad771284df53..22c380a05a926 100644 --- a/py/objdeque.c +++ b/py/objdeque.c @@ -208,7 +208,7 @@ static mp_obj_t deque_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { size_t offset = mp_get_index(self->base.type, deque_len(self), index, false); size_t index_val = self->i_get + offset; - if (index_val > self->alloc) { + if (index_val >= self->alloc) { index_val -= self->alloc; } From 6f327684b75ca882d34402f885897ada8e57592d Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 31 Oct 2024 12:41:17 +1100 Subject: [PATCH 05/22] extmod/modlwip: Fix IGMP address type when IPv6 is enabled. This was missed in 628abf8f25a7705a2810fffe2ca6ae652c532896. The the bug was that, when IPv6 is enabled, the `sizeof(ip_addr_t)` is much larger than IPv4 size, which is what's needed for IGMP addressing. Fixes issue #16100. Signed-off-by: Damien George --- extmod/modlwip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extmod/modlwip.c b/extmod/modlwip.c index 21c6f7264befa..0d38bf41b2051 100644 --- a/extmod/modlwip.c +++ b/extmod/modlwip.c @@ -1432,7 +1432,7 @@ static mp_obj_t lwip_socket_setsockopt(size_t n_args, const mp_obj_t *args) { case IP_DROP_MEMBERSHIP: { mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ); - if (bufinfo.len != sizeof(ip_addr_t) * 2) { + if (bufinfo.len != sizeof(MP_IGMP_IP_ADDR_TYPE) * 2) { mp_raise_ValueError(NULL); } From 164c5492481cb0d66e13f068818f9e2bbfa4dad6 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Fri, 1 Nov 2024 15:57:40 +1100 Subject: [PATCH 06/22] esp32/machine_pwm: Restore PWM support for ESP-IDF v5.0.x and v5.1.x. The cleanup in 548babf8 relies on some functions not available in older ESP-IDF. Temporarily restore them, until we drop support for ESP-IDF <5.2. PWM functionality should end up the same regardless of ESP-IDF version, and also no different from MicroPython V1.23. Signed-off-by: Angus Gratton --- ports/esp32/machine_pwm.c | 52 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/ports/esp32/machine_pwm.c b/ports/esp32/machine_pwm.c index 61efdfa18548b..0134fa2cc8c89 100644 --- a/ports/esp32/machine_pwm.c +++ b/ports/esp32/machine_pwm.c @@ -34,9 +34,12 @@ #include "py/mphal.h" #include "driver/ledc.h" #include "esp_err.h" -#include "esp_clk_tree.h" #include "soc/gpio_sig_map.h" +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 1, 0) +#include "esp_clk_tree.h" +#endif + #define PWM_DBG(...) // #define PWM_DBG(...) mp_printf(&mp_plat_print, __VA_ARGS__); mp_printf(&mp_plat_print, "\n"); @@ -208,7 +211,41 @@ static void configure_channel(machine_pwm_obj_t *self) { } } +// Temporary workaround for ledc_find_suitable_duty_resolution function only being added in IDF V5.2 +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 2, 0) +static uint32_t ledc_find_suitable_duty_resolution(uint32_t src_clk_freq, uint32_t timer_freq) { + // This implementation is based on the one used in Micropython v1.23 + + // Find the highest bit resolution for the requested frequency + unsigned int freq = src_clk_freq; + + int divider = (freq + timer_freq / 2) / timer_freq; // rounded + if (divider == 0) { + divider = 1; + } + float f = (float)freq / divider; // actual frequency + if (f <= 1.0) { + f = 1.0; + } + freq = (unsigned int)roundf((float)freq / f); + + unsigned int res = 0; + for (; freq > 1; freq >>= 1) { + ++res; + } + if (res == 0) { + res = 1; + } else if (res > HIGHEST_PWM_RES) { + // Limit resolution to HIGHEST_PWM_RES to match units of our duty + res = HIGHEST_PWM_RES; + } + + return res; +} +#endif + static void set_freq(machine_pwm_obj_t *self, unsigned int freq, ledc_timer_config_t *timer) { + esp_err_t err; if (freq != timer->freq_hz) { // Configure the new frequency and resolution timer->freq_hz = freq; @@ -228,10 +265,21 @@ static void set_freq(machine_pwm_obj_t *self, unsigned int freq, ledc_timer_conf } #endif uint32_t src_clk_freq = 0; - esp_err_t err = esp_clk_tree_src_get_freq_hz(timer->clk_cfg, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &src_clk_freq); + #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 1, 0) + err = esp_clk_tree_src_get_freq_hz(timer->clk_cfg, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &src_clk_freq); if (err != ESP_OK) { mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("unable to query source clock frequency %d"), (int)timer->clk_cfg); } + #else + // Simplified fallback logic for IDF V5.0.x, for targets with APB only. + src_clk_freq = APB_CLK_FREQ; // 80 MHz + #if SOC_LEDC_SUPPORT_REF_TICK + if (timer->clk_cfg == LEDC_USE_REF_TICK) { + src_clk_freq = REF_CLK_FREQ; // 1 MHz + } + #endif // SOC_LEDC_SUPPORT_REF_TICK + #endif // ESP_IDF_VERSION + timer->duty_resolution = ledc_find_suitable_duty_resolution(src_clk_freq, timer->freq_hz); // Set frequency From 72799f99739f99496fd82b06b0c55ad7f58d2290 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 6 Nov 2024 14:27:01 +1100 Subject: [PATCH 07/22] esp32: Workaround native code execution crash on ESP32-S2. Seemingly ESP-IDF incorrectly marks RTC FAST memory region as MALLOC_CAP_EXEC on ESP32-S2 when it isn't. This memory is the lowest priority, so it only is returned if D/IRAM is exhausted. Apply this workaround to treat the allocation as failed if it gives us non-executable RAM back, rather than crashing. This work was funded through GitHub Sponsors. Signed-off-by: Angus Gratton --- ports/esp32/main.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ports/esp32/main.c b/ports/esp32/main.c index 03dc0807a025c..18ef9d7354798 100644 --- a/ports/esp32/main.c +++ b/ports/esp32/main.c @@ -39,6 +39,7 @@ #include "esp_task.h" #include "esp_event.h" #include "esp_log.h" +#include "esp_memory_utils.h" #include "esp_psram.h" #include "py/cstack.h" @@ -237,6 +238,13 @@ void *esp_native_code_commit(void *buf, size_t len, void *reloc) { len = (len + 3) & ~3; size_t len_node = sizeof(native_code_node_t) + len; native_code_node_t *node = heap_caps_malloc(len_node, MALLOC_CAP_EXEC); + #if CONFIG_IDF_TARGET_ESP32S2 + // Workaround for ESP-IDF bug https://github.com/espressif/esp-idf/issues/14835 + if (node != NULL && !esp_ptr_executable(node)) { + free(node); + node = NULL; + } + #endif // CONFIG_IDF_TARGET_ESP32S2 if (node == NULL) { m_malloc_fail(len_node); } From c1a85bb6debb6f20a19d8699f2a009fadd4ed9d2 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 6 Nov 2024 12:43:04 +1100 Subject: [PATCH 08/22] tools/mpremote: Make sure stdout and stderr output appear in order. mpremote error messages now go to stderr, so make sure stdout is flushed before printing them. Also update the test runner to capture error messages. Signed-off-by: Damien George --- tools/mpremote/mpremote/main.py | 3 +++ tools/mpremote/tests/run-mpremote-tests.sh | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/mpremote/mpremote/main.py b/tools/mpremote/mpremote/main.py index 8c0a6cd224c32..e6e397020fe85 100644 --- a/tools/mpremote/mpremote/main.py +++ b/tools/mpremote/mpremote/main.py @@ -547,7 +547,10 @@ def main(): return 0 except CommandError as e: + # Make sure existing stdout appears before the error message on stderr. + sys.stdout.flush() print(f"{_PROG}: {e}", file=sys.stderr) + sys.stderr.flush() return 1 finally: do_disconnect(state) diff --git a/tools/mpremote/tests/run-mpremote-tests.sh b/tools/mpremote/tests/run-mpremote-tests.sh index 11d82c9bb3801..b25b5fd7d2966 100755 --- a/tools/mpremote/tests/run-mpremote-tests.sh +++ b/tools/mpremote/tests/run-mpremote-tests.sh @@ -16,7 +16,7 @@ for t in $TESTS; do TMP=$(mktemp -d) echo -n "${t}: " # Strip CR and replace the random temp dir with a token. - if env MPREMOTE=${MPREMOTE} TMP="${TMP}" "${t}" | tr -d '\r' | sed "s,${TMP},"'${TMP},g' > "${t}.out"; then + if env MPREMOTE=${MPREMOTE} TMP="${TMP}" "${t}" 2>&1 | tr -d '\r' | sed "s,${TMP},"'${TMP},g' > "${t}.out"; then if diff "${t}.out" "${t}.exp" > /dev/null; then echo "OK" else From 159b54b7da404bc9a8d60d8c989e33e11412e548 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 6 Nov 2024 12:44:50 +1100 Subject: [PATCH 09/22] tools/mpremote: Add test for forced copy. Signed-off-by: Damien George --- tools/mpremote/tests/test_filesystem.sh | 5 +++++ tools/mpremote/tests/test_filesystem.sh.exp | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/tools/mpremote/tests/test_filesystem.sh b/tools/mpremote/tests/test_filesystem.sh index b6d5a7febcb84..727efea90eb67 100755 --- a/tools/mpremote/tests/test_filesystem.sh +++ b/tools/mpremote/tests/test_filesystem.sh @@ -66,6 +66,11 @@ $MPREMOTE resume cp "${TMP}/a.py" :aaa $MPREMOTE resume cp "${TMP}/a.py" :bbb/b.py $MPREMOTE resume cat :aaa/a.py bbb/b.py +# Test cp -f (force copy). +echo ----- +$MPREMOTE resume cp -f "${TMP}/a.py" :aaa +$MPREMOTE resume cat :aaa/a.py + echo ----- $MPREMOTE resume rm :b.py c.py $MPREMOTE resume ls diff --git a/tools/mpremote/tests/test_filesystem.sh.exp b/tools/mpremote/tests/test_filesystem.sh.exp index 7220dc41e472c..b252bc7eb0d03 100644 --- a/tools/mpremote/tests/test_filesystem.sh.exp +++ b/tools/mpremote/tests/test_filesystem.sh.exp @@ -38,6 +38,10 @@ print("World") print("Hello") print("World") ----- +cp ${TMP}/a.py :aaa +print("Hello") +print("World") +----- rm :b.py rm :c.py ls : From 4e78c611b4b2ac2ee9eefb90b352fdc585f2a80a Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 6 Nov 2024 12:45:06 +1100 Subject: [PATCH 10/22] tools/mpremote: Support trailing slash on dest for non-recursive copy. This fixes a regression in db59e55fe7a0b67d3af868990468e7b8056afe42: prior to that commit `mpremote` supported trailing slashes on the destination of a normal (non-recursive) copy. Add back support for that, with the semantics that a trailing slash requires the destination to be an existing directory. Also add a test for this. Signed-off-by: Damien George --- tools/mpremote/mpremote/commands.py | 11 +++++++++-- tools/mpremote/tests/test_filesystem.sh | 5 +++++ tools/mpremote/tests/test_filesystem.sh.exp | 6 ++++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/tools/mpremote/mpremote/commands.py b/tools/mpremote/mpremote/commands.py index 2b1acea438084..f86befd080349 100644 --- a/tools/mpremote/mpremote/commands.py +++ b/tools/mpremote/mpremote/commands.py @@ -129,8 +129,15 @@ def _remote_path_basename(a): def do_filesystem_cp(state, src, dest, multiple, check_hash=False): if dest.startswith(":"): - dest_exists = state.transport.fs_exists(dest[1:]) - dest_isdir = dest_exists and state.transport.fs_isdir(dest[1:]) + dest_no_slash = dest.rstrip("/" + os.path.sep + (os.path.altsep or "")) + dest_exists = state.transport.fs_exists(dest_no_slash[1:]) + dest_isdir = dest_exists and state.transport.fs_isdir(dest_no_slash[1:]) + + # A trailing / on dest forces it to be a directory. + if dest != dest_no_slash: + if not dest_isdir: + raise CommandError("cp: destination is not a directory") + dest = dest_no_slash else: dest_exists = os.path.exists(dest) dest_isdir = dest_exists and os.path.isdir(dest) diff --git a/tools/mpremote/tests/test_filesystem.sh b/tools/mpremote/tests/test_filesystem.sh index 727efea90eb67..afeb7c91da8d6 100755 --- a/tools/mpremote/tests/test_filesystem.sh +++ b/tools/mpremote/tests/test_filesystem.sh @@ -71,6 +71,11 @@ echo ----- $MPREMOTE resume cp -f "${TMP}/a.py" :aaa $MPREMOTE resume cat :aaa/a.py +# Test cp where the destination has a trailing /. +echo ----- +$MPREMOTE resume cp "${TMP}/a.py" :aaa/ +$MPREMOTE resume cp "${TMP}/a.py" :aaa/a.py/ || echo "expect error" + echo ----- $MPREMOTE resume rm :b.py c.py $MPREMOTE resume ls diff --git a/tools/mpremote/tests/test_filesystem.sh.exp b/tools/mpremote/tests/test_filesystem.sh.exp index b252bc7eb0d03..82fe7d6bf78c5 100644 --- a/tools/mpremote/tests/test_filesystem.sh.exp +++ b/tools/mpremote/tests/test_filesystem.sh.exp @@ -42,6 +42,12 @@ cp ${TMP}/a.py :aaa print("Hello") print("World") ----- +cp ${TMP}/a.py :aaa/ +Up to date: aaa/a.py +cp ${TMP}/a.py :aaa/a.py/ +mpremote: cp: destination is not a directory +expect error +----- rm :b.py rm :c.py ls : From 0c580f71aedac16045f0ecad9cb586aa389d9cff Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 11 Nov 2024 12:04:57 +1100 Subject: [PATCH 11/22] esp32/modsocket: Fix getaddrinfo hints to set AI_CANONNAME. Because the `ai_canonname` field is subsequently used. ESP32_GENERIC_S3 (at least) crashes with IDF 5.2.3 without this set. Signed-off-by: Damien George --- ports/esp32/modsocket.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ports/esp32/modsocket.c b/ports/esp32/modsocket.c index 916eb79bd9265..7ea5e855d325e 100644 --- a/ports/esp32/modsocket.c +++ b/ports/esp32/modsocket.c @@ -213,7 +213,7 @@ static int mdns_getaddrinfo(const char *host_str, const char *port_str, #endif // MICROPY_HW_ENABLE_MDNS_QUERIES static void _getaddrinfo_inner(const mp_obj_t host, const mp_obj_t portx, - const struct addrinfo *hints, struct addrinfo **res) { + struct addrinfo *hints, struct addrinfo **res) { int retval = 0; *res = NULL; @@ -235,6 +235,9 @@ static void _getaddrinfo_inner(const mp_obj_t host, const mp_obj_t portx, MP_THREAD_GIL_EXIT(); + // The ai_canonname field is used below, so set the hint. + hints->ai_flags |= AI_CANONNAME; + #if MICROPY_HW_ENABLE_MDNS_QUERIES retval = mdns_getaddrinfo(host_str, port_str, hints, res); #endif @@ -264,7 +267,8 @@ static void _getaddrinfo_inner(const mp_obj_t host, const mp_obj_t portx, static void _socket_getaddrinfo(const mp_obj_t addrtuple, struct addrinfo **resp) { mp_obj_t *elem; mp_obj_get_array_fixed_n(addrtuple, 2, &elem); - _getaddrinfo_inner(elem[0], elem[1], NULL, resp); + struct addrinfo hints = { 0 }; + _getaddrinfo_inner(elem[0], elem[1], &hints, resp); } static mp_obj_t socket_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { From 20a6d82872263e0ef20de7c71b62456907244596 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 13 Nov 2024 14:21:29 +1100 Subject: [PATCH 12/22] extmod/vfs_blockdev: Support bool return from Python read/write blocks. Commit f4ab9d924790581989f2398fe30bbac5d680577f inadvertently broke some Python block devices, for example esp32 and stm32 SDCard classes. Those classes return a bool from their `readblocks` and `writeblocks` methods instead of an integer errno code. With that change, both `False` and `True` return values are now be interpreted as non-zero and hence the block device call fails. The fix in this commit is to allow a bool and explicitly convert `True` to 0 and `False` to `-MP_EIO`. Signed-off-by: Damien George --- extmod/vfs_blockdev.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/extmod/vfs_blockdev.c b/extmod/vfs_blockdev.c index a7c14b76ee368..d43c96b08f326 100644 --- a/extmod/vfs_blockdev.c +++ b/extmod/vfs_blockdev.c @@ -58,6 +58,13 @@ static int mp_vfs_blockdev_call_rw(mp_obj_t *args, size_t block_num, size_t bloc if (ret == mp_const_none) { return 0; } else { + // Some block devices return a bool indicating success, so + // convert those to an errno integer code. + if (ret == mp_const_true) { + return 0; + } else if (ret == mp_const_false) { + return -MP_EIO; + } // Block device functions are expected to return 0 on success // and negative integer on errors. Check for positive integer // results as some callers (i.e. littlefs) will produce corrupt From 67f893852af455a8fd938d67dda74f1465af0960 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 13 Nov 2024 18:14:47 +1100 Subject: [PATCH 13/22] extmod/network_cyw43: Fix isconnected() result on AP interface. This function is documented to return True if any stations are connected to the AP. Without this fix it returns True whenever the driver has brought the AP interface up. This work was funded through GitHub Sponsors. Signed-off-by: Angus Gratton --- extmod/network_cyw43.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/extmod/network_cyw43.c b/extmod/network_cyw43.c index 3066cac75d3b7..891e945de5118 100644 --- a/extmod/network_cyw43.c +++ b/extmod/network_cyw43.c @@ -311,7 +311,17 @@ static MP_DEFINE_CONST_FUN_OBJ_1(network_cyw43_disconnect_obj, network_cyw43_dis static mp_obj_t network_cyw43_isconnected(mp_obj_t self_in) { network_cyw43_obj_t *self = MP_OBJ_TO_PTR(self_in); - return mp_obj_new_bool(cyw43_tcpip_link_status(self->cyw, self->itf) == 3); + bool result = (cyw43_tcpip_link_status(self->cyw, self->itf) == CYW43_LINK_UP); + + if (result && self->itf == CYW43_ITF_AP) { + // For AP we need to not only know if the link is up, but also if any stations + // have associated. + uint8_t mac_buf[6]; + int num_stas = 1; + cyw43_wifi_ap_get_stas(self->cyw, &num_stas, mac_buf); + result = num_stas > 0; + } + return mp_obj_new_bool(result); } static MP_DEFINE_CONST_FUN_OBJ_1(network_cyw43_isconnected_obj, network_cyw43_isconnected); From 4f4d683ea58b69ae0906894b5fb98c9da9216ff9 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 19 Nov 2024 11:26:34 +1100 Subject: [PATCH 14/22] extmod/network_cyw43: Fix uninitialised variable in status('stations'). The `num_stas` was uninitialised and if it happened to take the value 0 then no results were returned. It now has the correct maximum value. Signed-off-by: Damien George --- extmod/network_cyw43.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/extmod/network_cyw43.c b/extmod/network_cyw43.c index 891e945de5118..cebc8deb0da91 100644 --- a/extmod/network_cyw43.c +++ b/extmod/network_cyw43.c @@ -361,13 +361,15 @@ static mp_obj_t network_cyw43_status(size_t n_args, const mp_obj_t *args) { if (self->itf != CYW43_ITF_AP) { mp_raise_ValueError(MP_ERROR_TEXT("AP required")); } - int num_stas; - uint8_t macs[32 * 6]; + static const unsigned mac_len = 6; + static const unsigned max_stas = 32; + int num_stas = max_stas; + uint8_t macs[max_stas * mac_len]; cyw43_wifi_ap_get_stas(self->cyw, &num_stas, macs); mp_obj_t list = mp_obj_new_list(num_stas, NULL); for (int i = 0; i < num_stas; ++i) { mp_obj_t tuple[1] = { - mp_obj_new_bytes(&macs[i * 6], 6), + mp_obj_new_bytes(&macs[i * mac_len], mac_len), }; ((mp_obj_list_t *)MP_OBJ_TO_PTR(list))->items[i] = mp_obj_new_tuple(1, tuple); } From 49b83ed44a0bd8ed2e8b4b82ae9ca09b47f4dbf9 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 13 Nov 2024 18:04:59 +1100 Subject: [PATCH 15/22] extmod/network_cyw43: Allow configuring active AP interface. Configuring the AP for cyw43 writes to some buffers that are only sent to the modem when the interface is brought up. This means you can't configure the AP after calling active(True), the new settings seem to be accepted but the radio doesn't change. This is different to the WLAN behaviour on other ports. The esp8266 port requires calling active(True) on the AP before configuring, even. Fix this by bouncing the AP interface after a config change, if it's active. Configuring with active(False) still works the same as before. Adds a static variable to track interface active state, rather than relying on the LWIP interface state. This is because the interface state is updated by a driver callback and there's a race: if code calls active(True) and then config(a=b) then the driver doesn't know it's active yet and the changes aren't correctly applied. It is possible this pattern will cause the AP to come up briefly with the default "PICOabcd" SSID before being reconfigured, however (due to the aforementioned race condition) it seems like this may not happen at all before the new config is applied. This work was funded through GitHub Sponsors. Signed-off-by: Angus Gratton --- extmod/network_cyw43.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/extmod/network_cyw43.c b/extmod/network_cyw43.c index cebc8deb0da91..02b022cb81327 100644 --- a/extmod/network_cyw43.c +++ b/extmod/network_cyw43.c @@ -60,6 +60,10 @@ typedef struct _network_cyw43_obj_t { static const network_cyw43_obj_t network_cyw43_wl_sta = { { &mp_network_cyw43_type }, &cyw43_state, CYW43_ITF_STA }; static const network_cyw43_obj_t network_cyw43_wl_ap = { { &mp_network_cyw43_type }, &cyw43_state, CYW43_ITF_AP }; +// Avoid race conditions with callbacks by tracking the last up or down request +// we have made for each interface. +static bool if_active[2]; + static void network_cyw43_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { network_cyw43_obj_t *self = MP_OBJ_TO_PTR(self_in); struct netif *netif = &self->cyw->netif[self->itf]; @@ -122,6 +126,10 @@ static MP_DEFINE_CONST_FUN_OBJ_3(network_cyw43_ioctl_obj, network_cyw43_ioctl); /*******************************************************************************/ // network API +static uint32_t get_country_code(void) { + return CYW43_COUNTRY(mod_network_country_code[0], mod_network_country_code[1], 0); +} + static mp_obj_t network_cyw43_deinit(mp_obj_t self_in) { network_cyw43_obj_t *self = MP_OBJ_TO_PTR(self_in); cyw43_deinit(self->cyw); @@ -132,10 +140,11 @@ static MP_DEFINE_CONST_FUN_OBJ_1(network_cyw43_deinit_obj, network_cyw43_deinit) static mp_obj_t network_cyw43_active(size_t n_args, const mp_obj_t *args) { network_cyw43_obj_t *self = MP_OBJ_TO_PTR(args[0]); if (n_args == 1) { - return mp_obj_new_bool(cyw43_tcpip_link_status(self->cyw, self->itf)); + return mp_obj_new_bool(if_active[self->itf]); } else { - uint32_t country = CYW43_COUNTRY(mod_network_country_code[0], mod_network_country_code[1], 0); - cyw43_wifi_set_up(self->cyw, self->itf, mp_obj_is_true(args[1]), country); + bool value = mp_obj_is_true(args[1]); + cyw43_wifi_set_up(self->cyw, self->itf, value, get_country_code()); + if_active[self->itf] = value; return mp_const_none; } } @@ -457,6 +466,10 @@ static mp_obj_t network_cyw43_config(size_t n_args, const mp_obj_t *args, mp_map mp_raise_TypeError(MP_ERROR_TEXT("can't specify pos and kw args")); } + // A number of these options only update buffers in memory, and + // won't do anything until the interface is cycled down and back up + bool cycle_active = false; + for (size_t i = 0; i < kwargs->alloc; ++i) { if (MP_MAP_SLOT_IS_FILLED(kwargs, i)) { mp_map_elem_t *e = &kwargs->table[i]; @@ -469,6 +482,7 @@ static mp_obj_t network_cyw43_config(size_t n_args, const mp_obj_t *args, mp_map } case MP_QSTR_channel: { cyw43_wifi_ap_set_channel(self->cyw, mp_obj_get_int(e->value)); + cycle_active = true; break; } case MP_QSTR_ssid: @@ -476,6 +490,7 @@ static mp_obj_t network_cyw43_config(size_t n_args, const mp_obj_t *args, mp_map size_t len; const char *str = mp_obj_str_get_data(e->value, &len); cyw43_wifi_ap_set_ssid(self->cyw, len, (const uint8_t *)str); + cycle_active = true; break; } case MP_QSTR_monitor: { @@ -495,6 +510,7 @@ static mp_obj_t network_cyw43_config(size_t n_args, const mp_obj_t *args, mp_map } case MP_QSTR_security: { cyw43_wifi_ap_set_auth(self->cyw, mp_obj_get_int(e->value)); + cycle_active = true; break; } case MP_QSTR_key: @@ -502,6 +518,7 @@ static mp_obj_t network_cyw43_config(size_t n_args, const mp_obj_t *args, mp_map size_t len; const char *str = mp_obj_str_get_data(e->value, &len); cyw43_wifi_ap_set_password(self->cyw, len, (const uint8_t *)str); + cycle_active = true; break; } case MP_QSTR_pm: { @@ -531,6 +548,13 @@ static mp_obj_t network_cyw43_config(size_t n_args, const mp_obj_t *args, mp_map } } + // If the interface is already active, cycle it down and up + if (cycle_active && if_active[self->itf]) { + uint32_t country = get_country_code(); + cyw43_wifi_set_up(self->cyw, self->itf, false, country); + cyw43_wifi_set_up(self->cyw, self->itf, true, country); + } + return mp_const_none; } } From 03bc561edb39073af28e0ee32a5e47543a0973c8 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 13 Nov 2024 10:16:25 +1100 Subject: [PATCH 16/22] esp32: Fix setting WLAN channel in AP mode. - Previously the call to esp_wifi_set_channel() would be immediately overridden by calling esp_wifi_config(...) with the previous channel set. - AP interface doesn't seem to need more than esp_wifi_config(...) to work. It will automatically configure 40MHz bandwidth and place the secondary channel using similar logic to what was being explicitly calculated here. - However, calling esp_wifi_set_channel() on the STA interface is necessary if using this interface with ESP-NOW (without connecting to an AP). So the esp_wifi_set_channel() call is kept in for this purpose. Without this, tests/multi_espnow/70_channel.py fails. This work was funded through GitHub Sponsors. Signed-off-by: Angus Gratton --- ports/esp32/network_wlan.c | 43 ++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/ports/esp32/network_wlan.c b/ports/esp32/network_wlan.c index 7e802166c116c..66b72e495e209 100644 --- a/ports/esp32/network_wlan.c +++ b/ports/esp32/network_wlan.c @@ -549,21 +549,38 @@ static mp_obj_t network_wlan_config(size_t n_args, const mp_obj_t *args, mp_map_ break; } case MP_QSTR_channel: { - uint8_t primary; - wifi_second_chan_t secondary; - // Get the current value of secondary - esp_exceptions(esp_wifi_get_channel(&primary, &secondary)); - primary = mp_obj_get_int(kwargs->table[i].value); - esp_err_t err = esp_wifi_set_channel(primary, secondary); - if (err == ESP_ERR_INVALID_ARG) { - // May need to swap secondary channel above to below or below to above - secondary = ( - (secondary == WIFI_SECOND_CHAN_ABOVE) - ? WIFI_SECOND_CHAN_BELOW - : (secondary == WIFI_SECOND_CHAN_BELOW) + uint8_t channel = mp_obj_get_int(kwargs->table[i].value); + if (self->if_id == ESP_IF_WIFI_AP) { + cfg.ap.channel = channel; + } else { + // This setting is only used to determine the + // starting channel for a scan, so it can result in + // slightly faster connection times. + cfg.sta.channel = channel; + + // This additional code to directly set the channel + // on the STA interface is only relevant for ESP-NOW + // (when there is no STA connection attempt.) + uint8_t old_primary; + wifi_second_chan_t secondary; + // Get the current value of secondary + esp_exceptions(esp_wifi_get_channel(&old_primary, &secondary)); + esp_err_t err = esp_wifi_set_channel(channel, secondary); + if (err == ESP_ERR_INVALID_ARG) { + // May need to swap secondary channel above to below or below to above + secondary = ( + (secondary == WIFI_SECOND_CHAN_ABOVE) + ? WIFI_SECOND_CHAN_BELOW + : (secondary == WIFI_SECOND_CHAN_BELOW) ? WIFI_SECOND_CHAN_ABOVE : WIFI_SECOND_CHAN_NONE); - esp_exceptions(esp_wifi_set_channel(primary, secondary)); + err = esp_wifi_set_channel(channel, secondary); + } + esp_exceptions(err); + if (channel != old_primary) { + // Workaround the ESP-IDF Wi-Fi stack sometimes taking a moment to change channels + mp_hal_delay_ms(1); + } } break; } From eb0027b82f77e9c9f072cecc1130c66ac287bc8a Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 6 Nov 2024 16:48:56 +1100 Subject: [PATCH 17/22] esp32: Use hardware version for touchpad macro defines. ESP32 has hardware V1 and S2/S3 has V2, and future chips may have different versions. This should still compile to the same binary before and after. This work was funded through GitHub Sponsors. Signed-off-by: Angus Gratton --- ports/esp32/machine_touchpad.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/ports/esp32/machine_touchpad.c b/ports/esp32/machine_touchpad.c index 7612063e51d4a..a35e7fccda215 100644 --- a/ports/esp32/machine_touchpad.c +++ b/ports/esp32/machine_touchpad.c @@ -29,12 +29,14 @@ #include "modmachine.h" #include "driver/gpio.h" -#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 +#if SOC_TOUCH_SENSOR_SUPPORTED -#if CONFIG_IDF_TARGET_ESP32 +#if SOC_TOUCH_VERSION_1 // ESP32 only #include "driver/touch_pad.h" -#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 +#elif SOC_TOUCH_VERSION_2 // All other SoCs with touch, to date #include "driver/touch_sensor.h" +#else +#error "Unknown touch hardware version" #endif typedef struct _mtp_obj_t { @@ -70,6 +72,8 @@ static const mtp_obj_t touchpad_obj[] = { {{&machine_touchpad_type}, GPIO_NUM_12, TOUCH_PAD_NUM12}, {{&machine_touchpad_type}, GPIO_NUM_13, TOUCH_PAD_NUM13}, {{&machine_touchpad_type}, GPIO_NUM_14, TOUCH_PAD_NUM14}, + #else + #error "Please add GPIO mapping for this SoC" #endif }; @@ -92,14 +96,14 @@ static mp_obj_t mtp_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_ if (!initialized) { touch_pad_init(); touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER); - #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 + #if TOUCH_HW_VER == 2 touch_pad_fsm_start(); #endif initialized = 1; } - #if CONFIG_IDF_TARGET_ESP32 + #if SOC_TOUCH_VERSION_1 esp_err_t err = touch_pad_config(self->touchpad_id, 0); - #elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 + #elif SOC_TOUCH_VERSION_2 esp_err_t err = touch_pad_config(self->touchpad_id); #endif if (err == ESP_OK) { @@ -110,10 +114,10 @@ static mp_obj_t mtp_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_ static mp_obj_t mtp_config(mp_obj_t self_in, mp_obj_t value_in) { mtp_obj_t *self = self_in; - #if CONFIG_IDF_TARGET_ESP32 + #if SOC_TOUCH_VERSION_1 uint16_t value = mp_obj_get_int(value_in); esp_err_t err = touch_pad_config(self->touchpad_id, value); - #elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 + #elif SOC_TOUCH_VERSION_2 esp_err_t err = touch_pad_config(self->touchpad_id); #endif if (err == ESP_OK) { @@ -125,10 +129,10 @@ MP_DEFINE_CONST_FUN_OBJ_2(mtp_config_obj, mtp_config); static mp_obj_t mtp_read(mp_obj_t self_in) { mtp_obj_t *self = self_in; - #if CONFIG_IDF_TARGET_ESP32 + #if SOC_TOUCH_VERSION_1 uint16_t value; esp_err_t err = touch_pad_read(self->touchpad_id, &value); - #elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 + #elif SOC_TOUCH_VERSION_2 uint32_t value; esp_err_t err = touch_pad_read_raw_data(self->touchpad_id, &value); #endif @@ -155,4 +159,4 @@ MP_DEFINE_CONST_OBJ_TYPE( locals_dict, &mtp_locals_dict ); -#endif +#endif // SOC_TOUCH_SENSOR_SUPPORTED From 33f50d4f20de3543f81a8404545eeeffb4aebbc0 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 6 Nov 2024 17:14:09 +1100 Subject: [PATCH 18/22] esp32: Fix machine.TouchPad startup on ESP32-S2 and S3. Closes #13178. TouchPad confirmed working on both chips, and fixes the the ESP32-S3 reading constant max value. Was unable to reproduce the bug on ESP32-S2 but this may be due to my test setup, and it still works with the fix. This work was funded through GitHub Sponsors. Signed-off-by: Angus Gratton --- ports/esp32/machine_touchpad.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ports/esp32/machine_touchpad.c b/ports/esp32/machine_touchpad.c index a35e7fccda215..48250280badaf 100644 --- a/ports/esp32/machine_touchpad.c +++ b/ports/esp32/machine_touchpad.c @@ -96,9 +96,6 @@ static mp_obj_t mtp_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_ if (!initialized) { touch_pad_init(); touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER); - #if TOUCH_HW_VER == 2 - touch_pad_fsm_start(); - #endif initialized = 1; } #if SOC_TOUCH_VERSION_1 @@ -107,6 +104,10 @@ static mp_obj_t mtp_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_ esp_err_t err = touch_pad_config(self->touchpad_id); #endif if (err == ESP_OK) { + #if SOC_TOUCH_VERSION_2 + touch_pad_fsm_start(); + #endif + return MP_OBJ_FROM_PTR(self); } mp_raise_ValueError(MP_ERROR_TEXT("Touch pad error")); From 948863c0b8ab4937d11aadf4cbb1b688bf66bf8f Mon Sep 17 00:00:00 2001 From: Corran Webster Date: Thu, 14 Nov 2024 10:15:10 +0000 Subject: [PATCH 19/22] extmod/modframebuf: Fix 0 radius bug in FrameBuffer.ellipse. This fixes a bug in FrameBuffer.ellipse where it goes into an infinite loop if both radii are 0. This fixes the bug with a simple pre-check to see if both radii are 0, and in that case sets a single pixel at the center. This is consistent with the behaviour of the method when called with just one of the radii set to 0, where it will draw a horizontal or vertical line of 1 pixel width. The pixel is set with setpixel_checked so it should handle out-of-bounds drawing correctly. This fix also includes three new tests: one for the default behaviour, one for drawing out-of-bounds, and one for when the sector mask is 0. Fixes issue #16053. Signed-off-by: Corran Webster --- extmod/modframebuf.c | 4 ++ tests/extmod/framebuf_ellipse.py | 15 +++++ tests/extmod/framebuf_ellipse.py.exp | 96 ++++++++++++++++++++++++++++ 3 files changed, 115 insertions(+) diff --git a/extmod/modframebuf.c b/extmod/modframebuf.c index cd0f50d104427..b718a66cc62fe 100644 --- a/extmod/modframebuf.c +++ b/extmod/modframebuf.c @@ -536,6 +536,10 @@ static mp_obj_t framebuf_ellipse(size_t n_args, const mp_obj_t *args_in) { } else { mask |= ELLIPSE_MASK_ALL; } + if (args[2] == 0 && args[3] == 0) { + setpixel_checked(self, args[0], args[1], args[4], mask & ELLIPSE_MASK_ALL); + return mp_const_none; + } mp_int_t two_asquare = 2 * args[2] * args[2]; mp_int_t two_bsquare = 2 * args[3] * args[3]; mp_int_t x = args[2]; diff --git a/tests/extmod/framebuf_ellipse.py b/tests/extmod/framebuf_ellipse.py index a4c784aff8762..ec0461e66ca03 100644 --- a/tests/extmod/framebuf_ellipse.py +++ b/tests/extmod/framebuf_ellipse.py @@ -63,3 +63,18 @@ def printbuf(): fbuf.fill(0) fbuf.ellipse(x, y, 6, 12, 0xAA, True) printbuf() + +# Draw an ellipse with both radius 0 +fbuf.fill(0) +fbuf.ellipse(15, 15, 0, 0, 0xFF, True) +printbuf() + +# Draw an ellipse with both radius 0 out of bounds +fbuf.fill(0) +fbuf.ellipse(45, 45, 0, 0, 0xFF, True) +printbuf() + +# Draw an ellipse with radius 0 and all sectors masked out +fbuf.fill(0) +fbuf.ellipse(15, 15, 0, 0, 0xFF, True, 0) +printbuf() diff --git a/tests/extmod/framebuf_ellipse.py.exp b/tests/extmod/framebuf_ellipse.py.exp index ae6ad1ee7e487..96a60c24da1f1 100644 --- a/tests/extmod/framebuf_ellipse.py.exp +++ b/tests/extmod/framebuf_ellipse.py.exp @@ -702,3 +702,99 @@ aaaaaaaaaaaaaaaaaaaaaa00000000000000000000000000000000000000 aaaaaaaaaaaaaaaaaaaaaa00000000000000000000000000000000000000 aaaaaaaaaaaaaaaaaaaaaa00000000000000000000000000000000000000 -->8-- +--8<-- +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000ff0000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +-->8-- +--8<-- +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +-->8-- +--8<-- +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000 +-->8-- From 7118942a8c03413e0e85b9b42fc9e1b167966d57 Mon Sep 17 00:00:00 2001 From: robert-hh Date: Wed, 27 Nov 2024 16:57:02 +0100 Subject: [PATCH 20/22] nrf/drivers/ticker: Reset slow ticker callback count on soft reboot. The micro:bit board (and probably other boards using the music or display module) locked up on soft reboot. Reason was a buffer overflow caused by an index counter, which was not reset on soft_reboot. That's fixed in this commit. Tested with a micro:bit board, performing a series of soft reboots. Signed-off-by: robert-hh --- ports/nrf/drivers/ticker.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/nrf/drivers/ticker.c b/ports/nrf/drivers/ticker.c index c2fa31e7c207b..e9c07c842ecd5 100644 --- a/ports/nrf/drivers/ticker.c +++ b/ports/nrf/drivers/ticker.c @@ -62,6 +62,7 @@ void ticker_init0(void) { #else NRFX_IRQ_PRIORITY_SET(FastTicker_IRQn, 2); #endif + m_num_of_slow_tickers = 0; NRFX_IRQ_PRIORITY_SET(SlowTicker_IRQn, 3); From 564ef28ad2ca1c0fb302ac3f46d5f2d07de353de Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 20 Nov 2024 16:15:20 +1100 Subject: [PATCH 21/22] py/objfloat: Workaround non-constant NAN definition on Windows MSVC. Recent MSVC versions have changed the definition of NAN to a non-constant expression! This is a bug, C standard says it should be a constant. Good explanation and workaround at: https://stackoverflow.com/a/79199887 This work was funded through GitHub Sponsors. Signed-off-by: Angus Gratton --- py/objfloat.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/py/objfloat.c b/py/objfloat.c index 5c90b1491cebf..0728fce3151fe 100644 --- a/py/objfloat.c +++ b/py/objfloat.c @@ -47,6 +47,13 @@ #define M_PI (3.14159265358979323846) #endif +// Workaround a bug in recent MSVC where NAN is no longer constant. +// (By redefining back to the previous MSVC definition of NAN) +#if defined(_MSC_VER) && _MSC_VER >= 1942 +#undef NAN +#define NAN (-(float)(((float)(1e+300 * 1e+300)) * 0.0F)) +#endif + typedef struct _mp_obj_float_t { mp_obj_base_t base; mp_float_t value; From ecfdd5d6f9be971852003c2049600dc7b3e2a838 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 29 Nov 2024 23:53:11 +1100 Subject: [PATCH 22/22] all: Bump version to 1.24.1. Signed-off-by: Damien George --- py/mpconfig.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/mpconfig.h b/py/mpconfig.h index caea0f4f7a3b8..a828f505ceac8 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -31,7 +31,7 @@ // are unavailable. #define MICROPY_VERSION_MAJOR 1 #define MICROPY_VERSION_MINOR 24 -#define MICROPY_VERSION_MICRO 0 +#define MICROPY_VERSION_MICRO 1 #define MICROPY_VERSION_PRERELEASE 0 // Combined version as a 32-bit number for convenience to allow version