From cc7eb77e7140aad64a889aa8e7015e8ffe4d3fc0 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Sun, 11 Oct 2026 21:02:30 -0700 Subject: [PATCH 1/2] zephyr-cp: report busio and usb_cdc timeouts in seconds The timeout getters divided kernel ticks by 1e6 as if they were microseconds, so usb_cdc write_timeout = 0.5 read back as 0.015625 on a 32768 Hz tick. Convert ticks to microseconds first, and report K_FOREVER as -1 so usb_cdc shows None. Setting usb_cdc timeout or write_timeout to None passed -1 to K_USEC(), which came out as zero. Store K_FOREVER instead, the value both start with. Co-Authored-By: Claude Opus 5.5 (1M context) --- ports/zephyr-cp/common-hal/busio/UART.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/ports/zephyr-cp/common-hal/busio/UART.c b/ports/zephyr-cp/common-hal/busio/UART.c index 97ab44bb8c1..d7b1678bd9b 100644 --- a/ports/zephyr-cp/common-hal/busio/UART.c +++ b/ports/zephyr-cp/common-hal/busio/UART.c @@ -254,20 +254,28 @@ void common_hal_busio_uart_set_baudrate(busio_uart_obj_t *self, uint32_t baudrat uart_configure(self->uart_device, &config); } +// K_FOREVER reads as -1, which usb_cdc reports as None. +static mp_float_t timeout_to_seconds(k_timeout_t timeout) { + if (K_TIMEOUT_EQ(timeout, K_FOREVER)) { + return -1; + } + return (mp_float_t)k_ticks_to_us_floor64(timeout.ticks) / MICROPY_FLOAT_CONST(1000000.0); +} + mp_float_t common_hal_busio_uart_get_timeout(busio_uart_obj_t *self) { - return (mp_float_t)self->timeout.ticks / 1000000.0; + return timeout_to_seconds(self->timeout); } void common_hal_busio_uart_set_timeout(busio_uart_obj_t *self, mp_float_t timeout) { - self->timeout = K_USEC((uint64_t)(timeout * 1000000)); + self->timeout = timeout < 0 ? K_FOREVER : K_USEC((uint64_t)(timeout * 1000000)); } mp_float_t common_hal_busio_uart_get_write_timeout(busio_uart_obj_t *self) { - return (mp_float_t)self->write_timeout.ticks / 1000000.0; + return timeout_to_seconds(self->write_timeout); } void common_hal_busio_uart_set_write_timeout(busio_uart_obj_t *self, mp_float_t write_timeout) { - self->write_timeout = K_USEC((uint64_t)(write_timeout * 1000000)); + self->write_timeout = write_timeout < 0 ? K_FOREVER : K_USEC((uint64_t)(write_timeout * 1000000)); } uint32_t common_hal_busio_uart_rx_characters_available(busio_uart_obj_t *self) { From 9c0689df214a4b79d62c36a72d4160183f4c4dcd Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Wed, 14 Oct 2026 13:02:31 -0700 Subject: [PATCH 2/2] zephyr-cp: native_sim test for busio UART timeout read-back native_sim ticks at 100 Hz, so before the fix timeout = 0.5 read back as 5e-05. The test sets 0.5, 2 and 0 on board.UART0() and checks each reads back in seconds. Co-Authored-By: Claude Opus 5.5 (1M context) --- ports/zephyr-cp/tests/test_busio_uart.py | 28 ++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 ports/zephyr-cp/tests/test_busio_uart.py diff --git a/ports/zephyr-cp/tests/test_busio_uart.py b/ports/zephyr-cp/tests/test_busio_uart.py new file mode 100644 index 00000000000..9d5a044e3ba --- /dev/null +++ b/ports/zephyr-cp/tests/test_busio_uart.py @@ -0,0 +1,28 @@ +# SPDX-FileCopyrightText: 2026 Mikey Sklar for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""busio.UART on native_sim, through the console UART.""" + +import pytest + +TIMEOUT_CODE = """\ +import board + +uart = board.UART0() +for t in (0.5, 2, 0): + uart.timeout = t + print("timeout", uart.timeout) +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": TIMEOUT_CODE}) +def test_uart_timeout_reads_back_in_seconds(circuitpython): + """timeout reads back the seconds it was set to, not raw kernel ticks.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "timeout 0.5" in output + assert "timeout 2.0" in output + assert "timeout 0.0" in output + assert "done" in output